From 7a665c3c2b4b18bb1c4f5ed747058a98a5fd8533 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Fri, 29 May 2020 15:16:10 +0200 Subject: [PATCH 01/31] Add github as an auth provider to the backend --- plugins/auth-backend/package.json | 14 ++-- plugins/auth-backend/src/providers/config.ts | 8 ++ .../auth-backend/src/providers/factories.ts | 2 + .../src/providers/github/index.ts | 17 ++++ .../src/providers/github/provider.ts | 84 +++++++++++++++++++ yarn.lock | 33 ++++---- 6 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 plugins/auth-backend/src/providers/github/index.ts create mode 100644 plugins/auth-backend/src/providers/github/provider.ts diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 9cb8017f15..505240853d 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -16,21 +16,23 @@ }, "dependencies": { "@backstage/backend-common": "^0.1.1-alpha.6", + "@types/cookie-parser": "^1.4.2", + "@types/passport": "^1.0.3", + "@types/passport-github2": "^1.2.4", + "@types/passport-google-oauth20": "^2.0.3", "compression": "^1.7.4", + "cookie-parser": "^1.4.5", "cors": "^2.8.5", "express": "^4.17.1", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.0", "helmet": "^3.22.0", "morgan": "^1.10.0", - "winston": "^3.2.1", - "yn": "^4.0.0", "passport": "^0.4.1", + "passport-github2": "^0.1.12", "passport-google-oauth20": "^2.0.0", - "cookie-parser": "^1.4.5", - "@types/passport": "^1.0.3", - "@types/passport-google-oauth20": "^2.0.3", - "@types/cookie-parser": "^1.4.2" + "winston": "^3.2.1", + "yn": "^4.0.0" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.6", diff --git a/plugins/auth-backend/src/providers/config.ts b/plugins/auth-backend/src/providers/config.ts index 45098afb89..dad87e0448 100644 --- a/plugins/auth-backend/src/providers/config.ts +++ b/plugins/auth-backend/src/providers/config.ts @@ -23,4 +23,12 @@ export const providers = [ callbackURL: 'http://localhost:7000/auth/google/handler/frame', }, }, + { + provider: 'github', + options: { + clientID: process.env.AUTH_GITHUB_CLIENT_ID!, + clientSecret: process.env.AUTH_GITHUB_CLIENT_SECRET!, + callbackURL: 'http://localhost:7000/auth/github/handler/frame', + }, + }, ]; diff --git a/plugins/auth-backend/src/providers/factories.ts b/plugins/auth-backend/src/providers/factories.ts index 0a1e639082..10e4153714 100644 --- a/plugins/auth-backend/src/providers/factories.ts +++ b/plugins/auth-backend/src/providers/factories.ts @@ -16,10 +16,12 @@ import { AuthProviderFactories, AuthProviderFactory } from './types'; import { GoogleAuthProvider } from './google'; +import { GithubAuthProvider } from './github'; export class ProviderFactories { private static readonly providerFactories: AuthProviderFactories = { google: GoogleAuthProvider, + github: GithubAuthProvider, }; public static getProviderFactory(providerId: string): AuthProviderFactory { diff --git a/plugins/auth-backend/src/providers/github/index.ts b/plugins/auth-backend/src/providers/github/index.ts new file mode 100644 index 0000000000..c3a48d35e0 --- /dev/null +++ b/plugins/auth-backend/src/providers/github/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { GithubAuthProvider } from './provider'; diff --git a/plugins/auth-backend/src/providers/github/provider.ts b/plugins/auth-backend/src/providers/github/provider.ts new file mode 100644 index 0000000000..1e8022e1cc --- /dev/null +++ b/plugins/auth-backend/src/providers/github/provider.ts @@ -0,0 +1,84 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import express from 'express'; +import { Strategy as GithubStrategy } from 'passport-github2'; +import { + executeFrameHandlerStrategy, + executeRedirectStrategy, + executeRefreshTokenStrategy, +} from '../PassportStrategyHelper'; +import { + OAuthProviderHandlers, + AuthProviderConfig, + RedirectInfo, + AuthInfoBase, + AuthInfoPrivate, +} from '../types'; + +export class GithubAuthProvider implements OAuthProviderHandlers { + private readonly providerConfig: AuthProviderConfig; + private readonly _strategy: GithubStrategy; + + constructor(providerConfig: AuthProviderConfig) { + this.providerConfig = providerConfig; + this._strategy = new GithubStrategy( + { ...this.providerConfig.options }, + ( + accessToken: any, + refreshToken: any, + params: any, + profile: any, + done: any, + ) => { + done( + undefined, + { + profile, + accessToken, + scope: 'user', // params.scope is an empty string here for some reason, so hardcoding for now + expiresInSeconds: params.expires_in, + }, + { refreshToken }, + ); + }, + ); + } + + async start(req: express.Request, options: any): Promise { + return await executeRedirectStrategy(req, this._strategy, options); + } + + async handler( + req: express.Request, + ): Promise<{ user: AuthInfoBase; info: AuthInfoPrivate }> { + return await executeFrameHandlerStrategy(req, this._strategy); + } + + async refresh(refreshToken: string, scope: string): Promise { + const { accessToken, params } = await executeRefreshTokenStrategy( + this._strategy, + refreshToken, + scope, + ); + + return { + accessToken, + expiresInSeconds: params.expires_in, + scope: params.scope, + }; + } +} diff --git a/yarn.lock b/yarn.lock index 8439f5b0b9..30537a6cac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4281,6 +4281,15 @@ resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/passport-github2@^1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@types/passport-github2/-/passport-github2-1.2.4.tgz#f56c386d1fe6435e359430e57adc1747a627bd86" + integrity sha512-dtGtA0Uyzk6ne3SrgQi/I1ClClLE3i7JmSiMaJgkGH8v1nbE9JdBpG7QWJ1XPlLdcf7EvoPdHmkWN2+Kln9y8g== + dependencies: + "@types/express" "*" + "@types/passport" "*" + "@types/passport-oauth2" "*" + "@types/passport-google-oauth20@^2.0.3": version "2.0.3" resolved "https://registry.npmjs.org/@types/passport-google-oauth20/-/passport-google-oauth20-2.0.3.tgz#f554ff6d39f395acff3f1d762e54462194dac8da" @@ -4290,15 +4299,7 @@ "@types/passport" "*" "@types/passport-oauth2" "*" -"@types/passport-oauth2-refresh@^1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@types/passport-oauth2-refresh/-/passport-oauth2-refresh-1.1.1.tgz#cbe466d4fcac36182fd75bf55279c0b1e953c382" - integrity sha512-Tw0JvfDPv9asgFPACd9oOGCaD/0/Uyi+QF7fmrJC74cJKC6I8N8wwhJJHyfd1N2E/qaLgTh431lhOa9jicpNdg== - dependencies: - "@types/oauth" "*" - "@types/passport-oauth2" "*" - -"@types/passport-oauth2@*", "@types/passport-oauth2@^1.4.9": +"@types/passport-oauth2@*": version "1.4.9" resolved "https://registry.npmjs.org/@types/passport-oauth2/-/passport-oauth2-1.4.9.tgz#134007c4b505a82548c9cb19094c5baeb2205c92" integrity sha512-QP0q+NVQOaIu2r0e10QWkiUA0Ya5mOBHRJN0UrI+LolMLOP1/VN4EVIpJ3xVwFo+xqNFRoFvFwJhBvKnk7kpUA== @@ -16103,6 +16104,13 @@ pascalcase@^0.1.1: resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +passport-github2@^0.1.12: + version "0.1.12" + resolved "https://registry.npmjs.org/passport-github2/-/passport-github2-0.1.12.tgz#a72ebff4fa52a35bc2c71122dcf470d1116f772c" + integrity sha512-3nPUCc7ttF/3HSP/k9sAXjz3SkGv5Nki84I05kSQPo01Jqq1NzJACgMblCK0fGcv9pKCG/KXU3AJRDGLqHLoIw== + dependencies: + passport-oauth2 "1.x.x" + passport-google-oauth20@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz#0d241b2d21ebd3dc7f2b60669ec4d587e3a674ef" @@ -16110,12 +16118,7 @@ passport-google-oauth20@^2.0.0: dependencies: passport-oauth2 "1.x.x" -passport-oauth2-refresh@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/passport-oauth2-refresh/-/passport-oauth2-refresh-2.0.0.tgz#7b19c77ff3cc000819c69f6ad9e318450f57b85e" - integrity sha512-yXvCB6nem/O+WThhiyI3TlPXpzSGY+9+hy9OTx9QF8e9GInplyRHxHaaOhFylKvnof9UmWHAufQFZk8cO1Fb2g== - -passport-oauth2@1.x.x, passport-oauth2@^1.5.0: +passport-oauth2@1.x.x: version "1.5.0" resolved "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108" integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ== From d3055d432162a17d06bc97a37d6fcab3053e6e67 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Fri, 29 May 2020 15:24:38 +0200 Subject: [PATCH 02/31] Add github to auth api --- packages/app/src/apis.ts | 11 ++ .../auth/github/GithubAuth.test.ts | 31 +++++ .../implementations/auth/github/GithubAuth.ts | 118 ++++++++++++++++++ .../apis/implementations/auth/github/index.ts | 18 +++ .../apis/implementations/auth/github/types.ts | 21 ++++ .../src/apis/implementations/auth/index.ts | 1 + 6 files changed, 200 insertions(+) create mode 100644 packages/core-api/src/apis/implementations/auth/github/GithubAuth.test.ts create mode 100644 packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts create mode 100644 packages/core-api/src/apis/implementations/auth/github/index.ts create mode 100644 packages/core-api/src/apis/implementations/auth/github/types.ts diff --git a/packages/app/src/apis.ts b/packages/app/src/apis.ts index 8d76c75d91..d6658c891c 100644 --- a/packages/app/src/apis.ts +++ b/packages/app/src/apis.ts @@ -25,9 +25,11 @@ import { featureFlagsApiRef, FeatureFlags, GoogleAuth, + GithubAuth, oauthRequestApiRef, OAuthRequestManager, googleAuthApiRef, + githubAuthApiRef, } from '@backstage/core'; import { @@ -63,6 +65,15 @@ builder.add( }), ); +builder.add( + githubAuthApiRef, + GithubAuth.create({ + apiOrigin: 'http://localhost:7000', + basePath: '/auth/', + oauthRequestApi, + }), +); + builder.add( techRadarApiRef, new TechRadar({ diff --git a/packages/core-api/src/apis/implementations/auth/github/GithubAuth.test.ts b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.test.ts new file mode 100644 index 0000000000..3d3da266fc --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import GithubAuth from './GithubAuth'; + +const theFuture = new Date(Date.now() + 3600000); + +describe('GithubAuth', () => { + it('should get refreshed access token', async () => { + const getSession = jest + .fn() + .mockResolvedValue({ accessToken: 'access-token', expiresAt: theFuture }); + const githubAuth = new GithubAuth({ getSession } as any); + + expect(await githubAuth.getAccessToken()).toBe('access-token'); + expect(getSession).toBeCalledTimes(1); + }); +}); diff --git a/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts new file mode 100644 index 0000000000..d20eaa54cb --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts @@ -0,0 +1,118 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import GithubIcon from '@material-ui/icons/AcUnit'; +import { DefaultAuthConnector } from '../../../../lib/AuthConnector'; +import { GithubSession } from './types'; +import { OAuthApi, AccessTokenOptions } from '../../../definitions/auth'; +import { OAuthRequestApi, AuthProvider } from '../../../definitions'; +import { SessionManager } from '../../../../lib/AuthSessionManager/types'; +import { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager'; + +type CreateOptions = { + // TODO(Rugvip): These two should be grabbed from global config when available, they're not unique to GithubAuth + apiOrigin: string; + basePath: string; + + oauthRequestApi: OAuthRequestApi; + + environment?: string; + provider?: AuthProvider & { id: string }; +}; + +export type GithubAuthResponse = { + accessToken: string; + idToken: string; + scope: string; + expiresInSeconds: number; +}; + +const DEFAULT_PROVIDER = { + id: 'github', + title: 'Github', + icon: GithubIcon, +}; + +class GithubAuth implements OAuthApi { + static create({ + apiOrigin, + basePath, + environment = 'dev', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + }: CreateOptions) { + const connector = new DefaultAuthConnector({ + apiOrigin, + basePath, + environment, + provider, + oauthRequestApi: oauthRequestApi, + sessionTransform(res: GithubAuthResponse): GithubSession { + return { + accessToken: res.accessToken, + scopes: GithubAuth.normalizeScopes(res.scope), + expiresAt: new Date(Date.now() + res.expiresInSeconds * 1000), + }; + }, + }); + + const sessionManager = new RefreshingAuthSessionManager({ + connector, + defaultScopes: new Set(['user']), + sessionScopes: session => session.scopes, + sessionShouldRefresh: session => { + const expiresInSec = (session.expiresAt.getTime() - Date.now()) / 1000; + return expiresInSec < 60 * 5; + }, + }); + + return new GithubAuth(sessionManager); + } + + constructor(private readonly sessionManager: SessionManager) {} + + async getAccessToken( + scope?: string | string[], + options?: AccessTokenOptions, + ) { + const normalizedScopes = GithubAuth.normalizeScopes(scope); + const session = await this.sessionManager.getSession({ + ...options, + scopes: normalizedScopes, + }); + if (session) { + return session.accessToken; + } + return ''; + } + + async logout() { + await this.sessionManager.removeSession(); + } + + static normalizeScopes(scopes?: string | string[]): Set { + if (!scopes) { + return new Set(); + } + + const scopeList = Array.isArray(scopes) + ? scopes + : scopes.split(/[\s]/).filter(Boolean); + + return new Set(scopeList); + } +} +export default GithubAuth; diff --git a/packages/core-api/src/apis/implementations/auth/github/index.ts b/packages/core-api/src/apis/implementations/auth/github/index.ts new file mode 100644 index 0000000000..9e1722f4a4 --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/github/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './types'; +export { default as GithubAuth } from './GithubAuth'; diff --git a/packages/core-api/src/apis/implementations/auth/github/types.ts b/packages/core-api/src/apis/implementations/auth/github/types.ts new file mode 100644 index 0000000000..282017b80d --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/github/types.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type GithubSession = { + accessToken: string; + scopes: Set; + expiresAt: Date; +}; diff --git a/packages/core-api/src/apis/implementations/auth/index.ts b/packages/core-api/src/apis/implementations/auth/index.ts index 5fa6644b2a..f13368b5c4 100644 --- a/packages/core-api/src/apis/implementations/auth/index.ts +++ b/packages/core-api/src/apis/implementations/auth/index.ts @@ -15,3 +15,4 @@ */ export * from './google'; +export * from './github'; From 9ccf617b82e9ff6f95429d9c3bd7b995070aa75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 28 May 2020 23:01:35 +0200 Subject: [PATCH 03/31] Add routes for add/delete entity to the catalog --- packages/backend/src/plugins/catalog.ts | 2 +- .../catalog/DatabaseEntitiesCatalog.test.ts | 110 ++++++++++++++++++ .../src/catalog/DatabaseEntitiesCatalog.ts | 75 +++++++++--- .../catalog/DatabaseLocationsCatalog.test.ts | 17 +-- .../src/catalog/DatabaseLocationsCatalog.ts | 5 +- .../src/catalog/StaticEntitiesCatalog.ts | 23 ++-- plugins/catalog-backend/src/catalog/index.ts | 14 ++- plugins/catalog-backend/src/catalog/types.ts | 9 +- ...atabase.test.ts => CommonDatabase.test.ts} | 52 ++++----- .../{Database.ts => CommonDatabase.ts} | 75 +++++------- .../src/database/DatabaseManager.test.ts | 10 +- .../src/database/DatabaseManager.ts | 79 +++++++++---- plugins/catalog-backend/src/database/index.ts | 12 +- .../src/database/search.test.ts | 4 +- .../catalog-backend/src/database/search.ts | 4 +- plugins/catalog-backend/src/database/types.ts | 81 ++++++++++++- .../src/ingestion/IngestionModels.ts | 4 +- .../src/service/router.test.ts | 101 +++++++++++++++- plugins/catalog-backend/src/service/router.ts | 15 ++- plugins/catalog-backend/src/service/util.ts | 22 +++- 20 files changed, 545 insertions(+), 169 deletions(-) create mode 100644 plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts rename plugins/catalog-backend/src/database/{Database.test.ts => CommonDatabase.test.ts} (90%) rename plugins/catalog-backend/src/database/{Database.ts => CommonDatabase.ts} (88%) diff --git a/packages/backend/src/plugins/catalog.ts b/packages/backend/src/plugins/catalog.ts index 7e843cc80b..9f5315fa08 100644 --- a/packages/backend/src/plugins/catalog.ts +++ b/packages/backend/src/plugins/catalog.ts @@ -41,7 +41,7 @@ export default async function ({ logger, database }: PluginEnvironment) { 10000, ); - const entitiesCatalog = new DatabaseEntitiesCatalog(db); + const entitiesCatalog = new DatabaseEntitiesCatalog(db, policy); const locationsCatalog = new DatabaseLocationsCatalog(db, ingestion); return await createRouter({ entitiesCatalog, locationsCatalog, logger }); diff --git a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts new file mode 100644 index 0000000000..d897584c95 --- /dev/null +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts @@ -0,0 +1,110 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Entity, EntityPolicy } from '@backstage/catalog-model'; +import type { Database } from '../database'; +import { DatabaseEntitiesCatalog } from './DatabaseEntitiesCatalog'; + +describe('DatabaseEntitiesCatalog', () => { + let db: Database; + let policy: EntityPolicy; + + beforeEach(() => { + // Since the database has a large API surface, we just leave it empty and + // let the tests insert whatever methods they need to call + db = ({ + transaction: jest.fn(async f => f('mock_tx')), + } as unknown) as Database; + policy = { enforce: jest.fn(async x => x) }; + }); + + describe('addOrUpdateEntity', () => { + it('adds when no given uid and no matching by name', async () => { + const entity: Entity = { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'c', + namespace: 'd', + }, + }; + + db.entities = jest.fn().mockResolvedValue([]); + db.addEntity = jest.fn().mockResolvedValue({ entity }); + + const catalog = new DatabaseEntitiesCatalog(db, policy); + const result = await catalog.addOrUpdateEntity(entity); + + expect(policy.enforce).toBeCalledWith(entity); + expect(db.entities).toHaveBeenCalledTimes(1); + expect(db.addEntity).toHaveBeenCalledTimes(1); + expect(result).toBe(entity); + }); + + it('updates when given uid', async () => { + const entity: Entity = { + apiVersion: 'a', + kind: 'b', + metadata: { + uid: 'uuuu', + name: 'c', + namespace: 'd', + }, + }; + + db.entities = jest.fn().mockResolvedValue([]); + db.updateEntity = jest.fn().mockResolvedValue({ entity }); + + const catalog = new DatabaseEntitiesCatalog(db, policy); + const result = await catalog.addOrUpdateEntity(entity); + + expect(policy.enforce).toBeCalledWith(entity); + expect(db.entities).toHaveBeenCalledTimes(0); + expect(db.updateEntity).toHaveBeenCalledTimes(1); + expect(result).toBe(entity); + }); + + it('update when no given uid and matching by name', async () => { + const added: Entity = { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'c', + namespace: 'd', + }, + }; + const existing: Entity = { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'c', + namespace: 'd', + }, + }; + + db.entities = jest.fn().mockResolvedValue([{ entity: existing }]); + db.updateEntity = jest.fn().mockResolvedValue({ entity: added }); + + const catalog = new DatabaseEntitiesCatalog(db, policy); + const result = await catalog.addOrUpdateEntity(added); + + expect(policy.enforce).toBeCalledWith(added); + expect(db.entities).toHaveBeenCalledTimes(1); + expect(db.updateEntity).toHaveBeenCalledTimes(1); + expect(result).toEqual(existing); + }); + }); +}); diff --git a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts index 972410a639..d13ac9a1ba 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts @@ -14,12 +14,15 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; -import { Database } from '../database'; -import { EntitiesCatalog, EntityFilters } from './types'; +import type { Entity, EntityPolicy } from '@backstage/catalog-model'; +import type { Database, DbEntityResponse, EntityFilters } from '../database'; +import type { EntitiesCatalog } from './types'; export class DatabaseEntitiesCatalog implements EntitiesCatalog { - constructor(private readonly database: Database) {} + constructor( + private readonly database: Database, + private readonly policy: EntityPolicy, + ) {} async entities(filters?: EntityFilters): Promise { const items = await this.database.transaction(tx => @@ -41,19 +44,59 @@ export class DatabaseEntitiesCatalog implements EntitiesCatalog { name: string, namespace: string | undefined, ): Promise { - const matches = await this.database.transaction(tx => - this.database.entities(tx, [ - { key: 'kind', values: [kind] }, - { key: 'name', values: [name] }, - { - key: 'namespace', - values: - !namespace || namespace === 'default' - ? [null, 'default'] - : [namespace], - }, - ]), + return await this.database.transaction(tx => + this.entityByNameInternal(tx, kind, name, namespace), ); + } + + async addOrUpdateEntity(entity: Entity): Promise { + await this.policy.enforce(entity); + return await this.database.transaction(async tx => { + let response: DbEntityResponse; + + if (entity.metadata.uid) { + response = await this.database.updateEntity(tx, { entity }); + } else { + const existing = await this.entityByNameInternal( + tx, + entity.kind, + entity.metadata.name, + entity.metadata.namespace, + ); + if (existing) { + response = await this.database.updateEntity(tx, { entity }); + } else { + response = await this.database.addEntity(tx, { entity }); + } + } + + return response.entity; + }); + } + + async removeEntityByUid(uid: string): Promise { + return await this.database.transaction(async tx => { + await this.database.removeEntity(tx, uid); + }); + } + + private async entityByNameInternal( + tx: unknown, + kind: string, + name: string, + namespace: string | undefined, + ): Promise { + const matches = await this.database.entities(tx, [ + { key: 'kind', values: [kind] }, + { key: 'name', values: [name] }, + { + key: 'namespace', + values: + !namespace || namespace === 'default' + ? [null, 'default'] + : [namespace], + }, + ]); return matches.length ? matches[0].entity : undefined; } diff --git a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts index 56a3b3828f..443b3bf6b0 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts @@ -14,11 +14,12 @@ * limitations under the License. */ import { getVoidLogger } from '@backstage/backend-common'; -import { Entity } from '@backstage/catalog-model'; -import knex from 'knex'; +import type { Entity } from '@backstage/catalog-model'; +import Knex from 'knex'; import path from 'path'; -import { Database } from '../database'; -import { IngestionModel } from '../ingestion/types'; +import { CommonDatabase } from '../database'; +import type { Database } from '../database'; +import type { IngestionModel } from '../ingestion/types'; import { DatabaseLocationsCatalog } from './DatabaseLocationsCatalog'; class MockIngestionModel implements IngestionModel { @@ -36,12 +37,12 @@ class MockIngestionModel implements IngestionModel { } describe('DatabaseLocationsCatalog', () => { - const database = knex({ + const knex = Knex({ client: 'sqlite3', connection: ':memory:', useNullAsDefault: true, }); - database.client.pool.on('createSuccess', (_eventId: any, resource: any) => { + knex.client.pool.on('createSuccess', (_eventId: any, resource: any) => { resource.run('PRAGMA foreign_keys = ON', () => {}); }); let db: Database; @@ -49,11 +50,11 @@ describe('DatabaseLocationsCatalog', () => { let ingestionModel: IngestionModel; beforeEach(async () => { - await database.migrate.latest({ + await knex.migrate.latest({ directory: path.resolve(__dirname, '../database/migrations'), loadExtensions: ['.ts'], }); - db = new Database(database, getVoidLogger()); + db = new CommonDatabase(knex, getVoidLogger()); ingestionModel = new MockIngestionModel(); catalog = new DatabaseLocationsCatalog(db, ingestionModel); }); diff --git a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts index b5841c8c2c..ae910e0b9b 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts @@ -14,13 +14,14 @@ * limitations under the License. */ -import { Database, DatabaseLocationUpdateLogEvent } from '../database'; +import type { Database } from '../database'; +import { DatabaseLocationUpdateLogEvent } from '../database/types'; import { IngestionModel } from '../ingestion/types'; import { AddLocation, Location, - LocationsCatalog, LocationResponse, + LocationsCatalog, } from './types'; export class DatabaseLocationsCatalog implements LocationsCatalog { diff --git a/plugins/catalog-backend/src/catalog/StaticEntitiesCatalog.ts b/plugins/catalog-backend/src/catalog/StaticEntitiesCatalog.ts index 64ac5f57d5..22bbd2e1a3 100644 --- a/plugins/catalog-backend/src/catalog/StaticEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/catalog/StaticEntitiesCatalog.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { NotFoundError } from '@backstage/backend-common'; -import { Entity } from '@backstage/catalog-model'; +import type { Entity } from '@backstage/catalog-model'; import lodash from 'lodash'; -import { EntitiesCatalog } from './types'; +import type { EntitiesCatalog } from './types'; export class StaticEntitiesCatalog implements EntitiesCatalog { private _entities: Entity[]; @@ -32,10 +31,7 @@ export class StaticEntitiesCatalog implements EntitiesCatalog { async entityByUid(uid: string): Promise { const item = this._entities.find(e => uid === e.metadata.uid); - if (!item) { - throw new NotFoundError('Entity cannot be found'); - } - return lodash.cloneDeep(item); + return item ? lodash.cloneDeep(item) : undefined; } async entityByName( @@ -49,9 +45,14 @@ export class StaticEntitiesCatalog implements EntitiesCatalog { name === e.metadata.name && namespace === e.metadata.namespace, ); - if (!item) { - throw new NotFoundError('Entity cannot be found'); - } - return lodash.cloneDeep(item); + return item ? lodash.cloneDeep(item) : undefined; + } + + async addOrUpdateEntity(): Promise { + throw new Error('Not supported'); + } + + async removeEntityByUid(): Promise { + throw new Error('Not supported'); } } diff --git a/plugins/catalog-backend/src/catalog/index.ts b/plugins/catalog-backend/src/catalog/index.ts index 58ae531944..6768268f34 100644 --- a/plugins/catalog-backend/src/catalog/index.ts +++ b/plugins/catalog-backend/src/catalog/index.ts @@ -14,7 +14,13 @@ * limitations under the License. */ -export * from './DatabaseEntitiesCatalog'; -export * from './DatabaseLocationsCatalog'; -export * from './StaticEntitiesCatalog'; -export * from './types'; +export { DatabaseEntitiesCatalog } from './DatabaseEntitiesCatalog'; +export { DatabaseLocationsCatalog } from './DatabaseLocationsCatalog'; +export { StaticEntitiesCatalog } from './StaticEntitiesCatalog'; +export { addLocationSchema } from './types'; +export type { + AddLocation, + EntitiesCatalog, + Location, + LocationsCatalog, +} from './types'; diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index 5f55de251f..61fba33ebf 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -16,17 +16,12 @@ import { Entity } from '@backstage/catalog-model'; import * as yup from 'yup'; +import type { EntityFilters } from '../database'; // // Entities // -export type EntityFilter = { - key: string; - values: (string | null)[]; -}; -export type EntityFilters = EntityFilter[]; - export type EntitiesCatalog = { entities(filters?: EntityFilters): Promise; entityByUid(uid: string): Promise; @@ -35,6 +30,8 @@ export type EntitiesCatalog = { namespace: string | undefined, name: string, ): Promise; + addOrUpdateEntity(entity: Entity): Promise; + removeEntityByUid(uid: string): Promise; }; // diff --git a/plugins/catalog-backend/src/database/Database.test.ts b/plugins/catalog-backend/src/database/CommonDatabase.test.ts similarity index 90% rename from plugins/catalog-backend/src/database/Database.test.ts rename to plugins/catalog-backend/src/database/CommonDatabase.test.ts index 6f15440fff..3b783a7691 100644 --- a/plugins/catalog-backend/src/database/Database.test.ts +++ b/plugins/catalog-backend/src/database/CommonDatabase.test.ts @@ -19,33 +19,33 @@ import { getVoidLogger, NotFoundError, } from '@backstage/backend-common'; +import type { Entity } from '@backstage/catalog-model'; import Knex from 'knex'; import path from 'path'; -import { +import { CommonDatabase } from './CommonDatabase'; +import { DatabaseLocationUpdateLogStatus } from './types'; +import type { + AddDatabaseLocation, DbEntityRequest, DbEntityResponse, - Database, - AddDatabaseLocation, DbLocationsRow, DbLocationsRowWithStatus, - DatabaseLocationUpdateLogStatus, -} from '.'; -import { Entity } from '@backstage/catalog-model'; +} from './types'; -describe('Database', () => { - let database: Knex; +describe('CommonDatabase', () => { + let knex: Knex; let entityRequest: DbEntityRequest; let entityResponse: DbEntityResponse; beforeEach(async () => { - database = Knex({ + knex = Knex({ client: 'sqlite3', connection: ':memory:', useNullAsDefault: true, }); - await database.raw('PRAGMA foreign_keys = ON'); - await database.migrate.latest({ + await knex.raw('PRAGMA foreign_keys = ON'); + await knex.migrate.latest({ directory: path.resolve(__dirname, 'migrations'), loadExtensions: ['.ts'], }); @@ -86,7 +86,7 @@ describe('Database', () => { }); it('manages locations', async () => { - const db = new Database(database, getVoidLogger()); + const db = new CommonDatabase(knex, getVoidLogger()); const input: AddDatabaseLocation = { type: 'a', target: 'b' }; const output: DbLocationsRowWithStatus = { id: expect.anything(), @@ -114,7 +114,7 @@ describe('Database', () => { it('instead of adding second location with the same target, returns existing one', async () => { // Prepare - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const input: AddDatabaseLocation = { type: 'a', target: 'b' }; const output1: DbLocationsRow = await catalog.addLocation(input); @@ -130,7 +130,7 @@ describe('Database', () => { describe('addEntity', () => { it('happy path: adds entity to empty database', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const added = await catalog.transaction(tx => catalog.addEntity(tx, entityRequest), ); @@ -139,7 +139,7 @@ describe('Database', () => { }); it('rejects adding the same-named entity twice', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); await catalog.transaction(tx => catalog.addEntity(tx, entityRequest)); await expect( catalog.transaction(tx => catalog.addEntity(tx, entityRequest)), @@ -147,7 +147,7 @@ describe('Database', () => { }); it('accepts adding the same-named entity twice if on different namespaces', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); entityRequest.entity.metadata.namespace = 'namespace1'; await catalog.transaction(tx => catalog.addEntity(tx, entityRequest)); entityRequest.entity.metadata.namespace = 'namespace2'; @@ -159,7 +159,7 @@ describe('Database', () => { describe('locationHistory', () => { it('outputs the history correctly', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const location: AddDatabaseLocation = { type: 'a', target: 'b' }; const { id: locationId } = await catalog.addLocation(location); @@ -198,7 +198,7 @@ describe('Database', () => { describe('updateEntity', () => { it('can read and no-op-update an entity', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const added = await catalog.transaction(tx => catalog.addEntity(tx, entityRequest), ); @@ -220,7 +220,7 @@ describe('Database', () => { }); it('can update name if uid matches', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const added = await catalog.transaction(tx => catalog.addEntity(tx, entityRequest), ); @@ -232,7 +232,7 @@ describe('Database', () => { }); it('can update fields if kind, name, and namespace match', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const added = await catalog.transaction(tx => catalog.addEntity(tx, entityRequest), ); @@ -246,7 +246,7 @@ describe('Database', () => { }); it('rejects if kind, name, but not namespace match', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const added = await catalog.transaction(tx => catalog.addEntity(tx, entityRequest), ); @@ -262,7 +262,7 @@ describe('Database', () => { }); it('fails to update an entity if etag does not match', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const added = await catalog.transaction(tx => catalog.addEntity(tx, entityRequest), ); @@ -275,7 +275,7 @@ describe('Database', () => { }); it('fails to update an entity if generation does not match', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const added = await catalog.transaction(tx => catalog.addEntity(tx, entityRequest), ); @@ -290,7 +290,7 @@ describe('Database', () => { describe('entities', () => { it('can get all entities with empty filters list', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const e1: Entity = { apiVersion: 'a', kind: 'k1', @@ -325,7 +325,7 @@ describe('Database', () => { }); it('can get all specific entities for matching filters (naive case)', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const entities: Entity[] = [ { apiVersion: 'a', kind: 'k1', metadata: { name: 'n' } }, { @@ -364,7 +364,7 @@ describe('Database', () => { }); it('can get all specific entities for matching filters with nulls (both missing and literal null value)', async () => { - const catalog = new Database(database, getVoidLogger()); + const catalog = new CommonDatabase(knex, getVoidLogger()); const entities: Entity[] = [ { apiVersion: 'a', kind: 'k1', metadata: { name: 'n' } }, { diff --git a/plugins/catalog-backend/src/database/Database.ts b/plugins/catalog-backend/src/database/CommonDatabase.ts similarity index 88% rename from plugins/catalog-backend/src/database/Database.ts rename to plugins/catalog-backend/src/database/CommonDatabase.ts index ea823a3da7..2dac08b9bc 100644 --- a/plugins/catalog-backend/src/database/Database.ts +++ b/plugins/catalog-backend/src/database/CommonDatabase.ts @@ -19,15 +19,15 @@ import { InputError, NotFoundError, } from '@backstage/backend-common'; -import { Entity, EntityMeta } from '@backstage/catalog-model'; +import type { Entity, EntityMeta } from '@backstage/catalog-model'; import Knex from 'knex'; import lodash from 'lodash'; import { v4 as uuidv4 } from 'uuid'; -import { Logger } from 'winston'; -import { EntityFilters } from '../catalog'; +import type { Logger } from 'winston'; import { buildEntitySearch } from './search'; -import { +import type { AddDatabaseLocation, + Database, DatabaseLocationUpdateLogEvent, DatabaseLocationUpdateLogStatus, DbEntitiesRow, @@ -36,6 +36,7 @@ import { DbEntityResponse, DbLocationsRow, DbLocationsRowWithStatus, + EntityFilters, } from './types'; function getStrippedMetadata(metadata: EntityMeta): EntityMeta { @@ -121,27 +122,13 @@ function generateEtag(): string { return Buffer.from(uuidv4(), 'utf8').toString('base64').replace(/[^\w]/g, ''); } -/** - * An abstraction on top of the underlying database, wrapping the basic CRUD - * needs. - */ -export class Database { +export class CommonDatabase implements Database { constructor( private readonly database: Knex, private readonly logger: Logger, ) {} - /** - * Runs a transaction. - * - * The callback is expected to make calls back into this class. When it - * completes, the transaction is closed. - * - * @param fn The callback that implements the transaction - */ - async transaction( - fn: (tx: Knex.Transaction) => Promise, - ): Promise { + async transaction(fn: (tx: unknown) => Promise): Promise { try { return await this.database.transaction(fn); } catch (e) { @@ -158,17 +145,12 @@ export class Database { } } - /** - * Adds a new entity to the catalog. - * - * @param tx An ongoing transaction - * @param request The entity being added - * @returns The added entity, with uid, etag and generation set - */ async addEntity( - tx: Knex.Transaction, + txOpaque: unknown, request: DbEntityRequest, ): Promise { + const tx = txOpaque as Knex.Transaction; + if (request.entity.metadata.uid !== undefined) { throw new InputError('May not specify uid for new entities'); } else if (request.entity.metadata.etag !== undefined) { @@ -198,25 +180,12 @@ export class Database { return { locationId: request.locationId, entity: newEntity }; } - /** - * Updates an existing entity in the catalog. - * - * The given entity must contain enough information to identify an already - * stored entity in the catalog - either by uid, or by kind + namespace + - * name. If no matching entity is found, the operation fails. - * - * If etag or generation are given, they are taken into account. Attempts to - * update a matching entity, but where the etag and/or generation are not - * equal to the passed values, will fail. - * - * @param tx An ongoing transaction - * @param request The entity being updated - * @returns The updated entity - */ async updateEntity( - tx: Knex.Transaction, + txOpaque: unknown, request: DbEntityRequest, ): Promise { + const tx = txOpaque as Knex.Transaction; + const { kind } = request.entity; const { uid, @@ -310,9 +279,11 @@ export class Database { } async entities( - tx: Knex.Transaction, + txOpaque: unknown, filters?: EntityFilters, ): Promise { + const tx = txOpaque as Knex.Transaction; + let builder = tx('entities'); for (const [index, filter] of (filters ?? []).entries()) { builder = builder @@ -337,11 +308,13 @@ export class Database { } async entity( - tx: Knex.Transaction, + txOpaque: unknown, kind: string, name: string, namespace?: string, ): Promise { + const tx = txOpaque as Knex.Transaction; + const rows = await tx('entities') .where({ kind, name, namespace: namespace || null }) .select(); @@ -353,6 +326,16 @@ export class Database { return toEntityResponse(rows[0]); } + async removeEntity(txOpaque: unknown, uid: string): Promise { + const tx = txOpaque as Knex.Transaction; + + const result = await tx('entities').where({ id: uid }).del(); + + if (!result) { + throw new NotFoundError(`Found no entity with ID ${uid}`); + } + } + async addLocation(location: AddDatabaseLocation): Promise { return await this.database.transaction(async tx => { const existingLocation = await tx('locations') diff --git a/plugins/catalog-backend/src/database/DatabaseManager.test.ts b/plugins/catalog-backend/src/database/DatabaseManager.test.ts index 6e18eaf419..0c28524f8d 100644 --- a/plugins/catalog-backend/src/database/DatabaseManager.test.ts +++ b/plugins/catalog-backend/src/database/DatabaseManager.test.ts @@ -15,16 +15,16 @@ */ import { getVoidLogger } from '@backstage/backend-common'; +import type { Entity, EntityPolicy } from '@backstage/catalog-model'; import Knex from 'knex'; -import { Database } from './Database'; +import type { IngestionModel } from '../ingestion/types'; import { DatabaseManager } from './DatabaseManager'; -import { - DatabaseLocationUpdateLogStatus, +import { DatabaseLocationUpdateLogStatus } from './types'; +import type { + Database, DbLocationsRow, DbLocationsRowWithStatus, } from './types'; -import { EntityPolicy, Entity } from '@backstage/catalog-model'; -import { IngestionModel } from '..'; describe('DatabaseManager', () => { describe('refreshLocations', () => { diff --git a/plugins/catalog-backend/src/database/DatabaseManager.ts b/plugins/catalog-backend/src/database/DatabaseManager.ts index 05b6eaef8d..4268dc4146 100644 --- a/plugins/catalog-backend/src/database/DatabaseManager.ts +++ b/plugins/catalog-backend/src/database/DatabaseManager.ts @@ -14,25 +14,26 @@ * limitations under the License. */ -import { Entity, EntityPolicy } from '@backstage/catalog-model'; +import type { Entity, EntityPolicy } from '@backstage/catalog-model'; import Knex from 'knex'; import lodash from 'lodash'; import path from 'path'; import { Logger } from 'winston'; -import { IngestionModel } from '../ingestion/types'; -import { Database } from './Database'; -import { DatabaseLocationUpdateLogStatus, DbEntityRequest } from './types'; +import type { IngestionModel } from '../ingestion/types'; +import { CommonDatabase } from './CommonDatabase'; +import { DatabaseLocationUpdateLogStatus } from './types'; +import type { Database, DbEntityRequest } from './types'; export class DatabaseManager { public static async createDatabase( - database: Knex, + knex: Knex, logger: Logger, ): Promise { - await database.migrate.latest({ + await knex.migrate.latest({ directory: path.resolve(__dirname, 'migrations'), loadExtensions: ['.js'], }); - return new Database(database, logger); + return new CommonDatabase(knex, logger); } private static async logUpdateSuccess( @@ -158,22 +159,58 @@ export class DatabaseManager { }); } - private static entitiesAreEqual(first: Entity, second: Entity) { - const firstClone = lodash.cloneDeep(first); - const secondClone = lodash.cloneDeep(second); + private static entitiesAreEqual(previous: Entity, next: Entity) { + if ( + previous.apiVersion !== next.apiVersion || + previous.kind !== next.kind || + !lodash.isEqual(previous.spec, next.spec) // Accept that {} !== undefined + ) { + return false; + } + + // Since the next annotations get merged into the previous, extract only + // the overlapping keys and check if their values match. + if (next.metadata.annotations) { + if (!previous.metadata.annotations) { + return false; + } + if ( + !lodash.isEqual( + next.metadata.annotations, + lodash.pick( + previous.metadata.annotations, + Object.keys(next.metadata.annotations), + ), + ) + ) { + return false; + } + } + + const e1 = lodash.cloneDeep(previous); + const e2 = lodash.cloneDeep(next); + + if (!e1.metadata.labels) { + e1.metadata.labels = {}; + } + if (!e2.metadata.labels) { + e2.metadata.labels = {}; + } // Remove generated fields - if (firstClone.metadata) { - delete firstClone.metadata.uid; - delete firstClone.metadata.etag; - delete firstClone.metadata.generation; - } - if (secondClone.metadata) { - delete secondClone.metadata.uid; - delete secondClone.metadata.etag; - delete secondClone.metadata.generation; - } + delete e1.metadata.uid; + delete e1.metadata.etag; + delete e1.metadata.generation; + delete e2.metadata.uid; + delete e2.metadata.etag; + delete e2.metadata.generation; - return lodash.isEqual(firstClone, secondClone); + // Remove already compared things + delete e1.metadata.annotations; + delete e1.spec; + delete e2.metadata.annotations; + delete e2.spec; + + return lodash.isEqual(e1, e2); } } diff --git a/plugins/catalog-backend/src/database/index.ts b/plugins/catalog-backend/src/database/index.ts index 616808fb67..565a41cfb2 100644 --- a/plugins/catalog-backend/src/database/index.ts +++ b/plugins/catalog-backend/src/database/index.ts @@ -14,6 +14,12 @@ * limitations under the License. */ -export * from './Database'; -export * from './DatabaseManager'; -export * from './types'; +export { CommonDatabase } from './CommonDatabase'; +export { DatabaseManager } from './DatabaseManager'; +export type { + Database, + DbEntityRequest, + DbEntityResponse, + EntityFilter, + EntityFilters, +} from './types'; diff --git a/plugins/catalog-backend/src/database/search.test.ts b/plugins/catalog-backend/src/database/search.test.ts index 8f011fb250..38a2d40e74 100644 --- a/plugins/catalog-backend/src/database/search.test.ts +++ b/plugins/catalog-backend/src/database/search.test.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; +import type { Entity } from '@backstage/catalog-model'; import { buildEntitySearch, visitEntityPart } from './search'; -import { DbEntitiesSearchRow } from './types'; +import type { DbEntitiesSearchRow } from './types'; describe('search', () => { describe('visitEntityPart', () => { diff --git a/plugins/catalog-backend/src/database/search.ts b/plugins/catalog-backend/src/database/search.ts index 87fc59185d..c14acb6661 100644 --- a/plugins/catalog-backend/src/database/search.ts +++ b/plugins/catalog-backend/src/database/search.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; -import { DbEntitiesSearchRow } from './types'; +import type { Entity } from '@backstage/catalog-model'; +import type { DbEntitiesSearchRow } from './types'; // Search entries that start with these prefixes, also get a shorthand without // that prefix diff --git a/plugins/catalog-backend/src/database/types.ts b/plugins/catalog-backend/src/database/types.ts index 0b9485242f..f69a7353c7 100644 --- a/plugins/catalog-backend/src/database/types.ts +++ b/plugins/catalog-backend/src/database/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; +import type { Entity } from '@backstage/catalog-model'; import * as yup from 'yup'; export type DbEntitiesRow = { @@ -83,3 +83,82 @@ export type DatabaseLocationUpdateLogEvent = { created_at?: string; message?: string; }; + +export type EntityFilter = { + key: string; + values: (string | null)[]; +}; +export type EntityFilters = EntityFilter[]; + +/** + * An abstraction on top of the underlying database, wrapping the basic CRUD + * needs. + */ +export type Database = { + /** + * Runs a transaction. + * + * The callback is expected to make calls back into this class. When it + * completes, the transaction is closed. + * + * @param fn The callback that implements the transaction + */ + transaction(fn: (tx: unknown) => Promise): Promise; + + /** + * Adds a new entity to the catalog. + * + * @param tx An ongoing transaction + * @param request The entity being added + * @returns The added entity, with uid, etag and generation set + */ + addEntity(tx: unknown, request: DbEntityRequest): Promise; + + /** + * Updates an existing entity in the catalog. + * + * The given entity must contain enough information to identify an already + * stored entity in the catalog - either by uid, or by kind + namespace + + * name. If no matching entity is found, the operation fails. + * + * If etag or generation are given, they are taken into account. Attempts to + * update a matching entity, but where the etag and/or generation are not + * equal to the passed values, will fail. + * + * @param tx An ongoing transaction + * @param request The entity being updated + * @returns The updated entity + */ + updateEntity( + tx: unknown, + request: DbEntityRequest, + ): Promise; + + entities(tx: unknown, filters?: EntityFilters): Promise; + + entity( + tx: unknown, + kind: string, + name: string, + namespace?: string, + ): Promise; + + removeEntity(tx: unknown, uid: string): Promise; + + addLocation(location: AddDatabaseLocation): Promise; + + removeLocation(id: string): Promise; + + location(id: string): Promise; + + locations(): Promise; + + locationHistory(id: string): Promise; + + addLocationUpdateLogEvent( + locationId: string, + status: DatabaseLocationUpdateLogStatus, + entityName?: string, + message?: string, + ): Promise; +}; diff --git a/plugins/catalog-backend/src/ingestion/IngestionModels.ts b/plugins/catalog-backend/src/ingestion/IngestionModels.ts index def6f1fa5c..8febdecd18 100644 --- a/plugins/catalog-backend/src/ingestion/IngestionModels.ts +++ b/plugins/catalog-backend/src/ingestion/IngestionModels.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { EntityPolicy, EntityPolicies } from '@backstage/catalog-model'; +import { EntityPolicies, EntityPolicy } from '@backstage/catalog-model'; +import { DescriptorParsers } from './descriptor'; import { DescriptorParser, ReaderOutput } from './descriptor/parsers/types'; import { LocationReader, LocationReaders } from './source'; import { IngestionModel } from './types'; -import { DescriptorParsers } from './descriptor'; export class IngestionModels implements IngestionModel { private readonly reader: LocationReader; diff --git a/plugins/catalog-backend/src/service/router.test.ts b/plugins/catalog-backend/src/service/router.test.ts index 8c7946816c..4092ed1395 100644 --- a/plugins/catalog-backend/src/service/router.test.ts +++ b/plugins/catalog-backend/src/service/router.test.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { Entity } from '@backstage/catalog-model'; +import { getVoidLogger, NotFoundError } from '@backstage/backend-common'; +import type { Entity } from '@backstage/catalog-model'; import express from 'express'; import request from 'supertest'; import { EntitiesCatalog, Location, LocationsCatalog } from '../catalog'; @@ -25,6 +25,9 @@ class MockEntitiesCatalog implements EntitiesCatalog { entities = jest.fn(); entityByUid = jest.fn(); entityByName = jest.fn(); + addEntity = jest.fn(); + addOrUpdateEntity = jest.fn(); + removeEntityByUid = jest.fn(); } class MockLocationsCatalog implements LocationsCatalog { @@ -36,7 +39,7 @@ class MockLocationsCatalog implements LocationsCatalog { } describe('createRouter', () => { - describe('entities', () => { + describe('GET /entities', () => { it('happy path: lists entities', async () => { const entities: Entity[] = [ { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, @@ -77,7 +80,7 @@ describe('createRouter', () => { }); }); - describe('entityByUid', () => { + describe('GET /entities/by-uid/:uid', () => { it('can fetch entity by uid', async () => { const entity: Entity = { apiVersion: 'a', @@ -118,7 +121,7 @@ describe('createRouter', () => { }); }); - describe('entityByName', () => { + describe('GET /entities/by-name/:kind/:namespace/:name', () => { it('can fetch entity by name', async () => { const entity: Entity = { apiVersion: 'a', @@ -160,7 +163,91 @@ describe('createRouter', () => { }); }); - describe('locations', () => { + describe('POST /entities', () => { + it('requires a body', async () => { + const catalog = new MockEntitiesCatalog(); + const router = await createRouter({ + entitiesCatalog: catalog, + logger: getVoidLogger(), + }); + + const app = express().use(router); + const response = await request(app) + .post('/entities') + .set('Content-Type', 'application/json') + .send(); + + expect(response.status).toEqual(400); + expect(response.text).toMatch(/body/); + expect(catalog.addOrUpdateEntity).not.toHaveBeenCalled(); + }); + + it('passes the body down', async () => { + const entity: Entity = { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'c', + namespace: 'd', + }, + }; + + const catalog = new MockEntitiesCatalog(); + catalog.addOrUpdateEntity.mockResolvedValue(entity); + + const router = await createRouter({ + entitiesCatalog: catalog, + logger: getVoidLogger(), + }); + + const app = express().use(router); + const response = await request(app) + .post('/entities') + .send(entity) + .set('Content-Type', 'application/json'); + + expect(response.status).toEqual(200); + expect(response.body).toEqual(entity); + expect(catalog.addOrUpdateEntity).toHaveBeenCalledTimes(1); + expect(catalog.addOrUpdateEntity).toHaveBeenNthCalledWith(1, entity); + }); + }); + + describe('DELETE /entities/by-uid/:uid', () => { + it('can remove', async () => { + const catalog = new MockEntitiesCatalog(); + catalog.removeEntityByUid.mockResolvedValue(undefined); + + const router = await createRouter({ + entitiesCatalog: catalog, + logger: getVoidLogger(), + }); + + const app = express().use(router); + const response = await request(app).delete('/entities/by-uid/apa'); + + expect(response.status).toEqual(204); + expect(catalog.removeEntityByUid).toHaveBeenCalledTimes(1); + }); + + it('responds with a 404 for missing entities', async () => { + const catalog = new MockEntitiesCatalog(); + catalog.removeEntityByUid.mockRejectedValue(new NotFoundError('nope')); + + const router = await createRouter({ + entitiesCatalog: catalog, + logger: getVoidLogger(), + }); + + const app = express().use(router); + const response = await request(app).delete('/entities/by-uid/apa'); + + expect(response.status).toEqual(404); + expect(catalog.removeEntityByUid).toHaveBeenCalledTimes(1); + }); + }); + + describe('GET /locations', () => { it('happy path: lists locations', async () => { const locations: Location[] = [{ id: 'a', type: 'b', target: 'c' }]; @@ -178,7 +265,9 @@ describe('createRouter', () => { expect(response.status).toEqual(200); expect(response.body).toEqual(locations); }); + }); + describe('POST /locations', () => { it('rejects malformed locations', async () => { const location = ({ id: 'a', diff --git a/plugins/catalog-backend/src/service/router.ts b/plugins/catalog-backend/src/service/router.ts index 32bba44984..f5adbd84ca 100644 --- a/plugins/catalog-backend/src/service/router.ts +++ b/plugins/catalog-backend/src/service/router.ts @@ -15,16 +15,17 @@ */ import { errorHandler, InputError } from '@backstage/backend-common'; +import { Entity } from '@backstage/catalog-model'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; import { addLocationSchema, EntitiesCatalog, - EntityFilters, LocationsCatalog, } from '../catalog'; -import { validateRequestBody } from './util'; +import { EntityFilters } from '../database'; +import { requireRequestBody, validateRequestBody } from './util'; export interface RouterOptions { entitiesCatalog?: EntitiesCatalog; @@ -47,6 +48,11 @@ export async function createRouter( const entities = await entitiesCatalog.entities(filters); res.status(200).send(entities); }) + .post('/entities', async (req, res) => { + const body = await requireRequestBody(req); + const result = await entitiesCatalog.addOrUpdateEntity(body as Entity); + res.status(200).send(result); + }) .get('/entities/by-uid/:uid', async (req, res) => { const { uid } = req.params; const entity = await entitiesCatalog.entityByUid(uid); @@ -55,6 +61,11 @@ export async function createRouter( } res.status(200).send(entity); }) + .delete('/entities/by-uid/:uid', async (req, res) => { + const { uid } = req.params; + await entitiesCatalog.removeEntityByUid(uid); + res.status(204).send(); + }) .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => { const { kind, namespace, name } = req.params; const entity = await entitiesCatalog.entityByName( diff --git a/plugins/catalog-backend/src/service/util.ts b/plugins/catalog-backend/src/service/util.ts index 4c37154c48..39692030e3 100644 --- a/plugins/catalog-backend/src/service/util.ts +++ b/plugins/catalog-backend/src/service/util.ts @@ -16,12 +16,10 @@ import { InputError } from '@backstage/backend-common'; import { Request } from 'express'; +import lodash from 'lodash'; import yup from 'yup'; -export async function validateRequestBody( - req: Request, - schema: yup.Schema, -): Promise { +export async function requireRequestBody(req: Request): Promise { const contentType = req.header('content-type'); if (!contentType) { throw new InputError('Content-Type missing'); @@ -32,13 +30,27 @@ export async function validateRequestBody( const body = req.body; if (!body) { throw new InputError('Missing request body'); + } else if (!lodash.isPlainObject(body)) { + throw new InputError('Expected body to be a JSON object'); + } else if (Object.keys(body).length === 0) { + // Because of how express.json() translates the empty body to {} + throw new InputError('Empty request body'); } + return body; +} + +export async function validateRequestBody( + req: Request, + schema: yup.Schema, +): Promise { + const body = await requireRequestBody(req); + try { await schema.validate(body, { strict: true }); } catch (e) { throw new InputError(`Malformed request: ${e}`); } - return body as T; + return (body as unknown) as T; } From 43795b857664d21d2c700cc4bada82431abe42ba Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 31 May 2020 19:37:38 +0200 Subject: [PATCH 04/31] packages/dev-utils: added addRootChild to DevAppBuilder --- packages/dev-utils/src/devApp/render.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx index 72c9581a84..5a28a43e8b 100644 --- a/packages/dev-utils/src/devApp/render.tsx +++ b/packages/dev-utils/src/devApp/render.tsx @@ -15,7 +15,7 @@ */ import { hot } from 'react-hot-loader/root'; -import React, { FC, ComponentType } from 'react'; +import React, { FC, ComponentType, ReactNode } from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import BookmarkIcon from '@material-ui/icons/Bookmark'; @@ -43,6 +43,7 @@ type BackstagePlugin = ReturnType; class DevAppBuilder { private readonly plugins = new Array(); private readonly factories = new Array>(); + private readonly rootChildren = new Array(); /** * Register one or more plugins to render in the dev app @@ -62,6 +63,16 @@ class DevAppBuilder { return this; } + /** + * Adds a React node to place just inside the App Provider. + * + * Useful for adding more global components like the AlertDisplay. + */ + addRootChild(node: ReactNode): DevAppBuilder { + this.rootChildren.push(node); + return this; + } + /** * Build a DevApp component using the resources registered so far */ @@ -79,6 +90,7 @@ class DevAppBuilder { return ( + {this.rootChildren} {sidebar} From 6f955a536678eb91c43405f751549666a72b1144 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 31 May 2020 19:40:58 +0200 Subject: [PATCH 05/31] packages/dev-utils: add oauthRequestApi factory + dialog --- packages/dev-utils/src/devApp/apiFactories.ts | 8 ++++++++ packages/dev-utils/src/devApp/render.tsx | 2 ++ 2 files changed, 10 insertions(+) diff --git a/packages/dev-utils/src/devApp/apiFactories.ts b/packages/dev-utils/src/devApp/apiFactories.ts index 162375cf1c..967918d87a 100644 --- a/packages/dev-utils/src/devApp/apiFactories.ts +++ b/packages/dev-utils/src/devApp/apiFactories.ts @@ -22,6 +22,8 @@ import { createApiFactory, ErrorAlerter, AlertApiForwarder, + oauthRequestApiRef, + OAuthRequestManager, } from '@backstage/core'; // TODO(rugvip): We should likely figure out how to reuse all of these between apps @@ -41,3 +43,9 @@ export const errorApiFactory = createApiFactory({ factory: ({ alertApi }) => new ErrorAlerter(alertApi, new ErrorApiForwarder()), }); + +export const oauthRequestApiFactory = createApiFactory({ + implements: oauthRequestApiRef, + deps: {}, + factory: () => new OAuthRequestManager(), +}); diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx index 5a28a43e8b..b174a0447f 100644 --- a/packages/dev-utils/src/devApp/render.tsx +++ b/packages/dev-utils/src/devApp/render.tsx @@ -30,6 +30,7 @@ import { ApiTestRegistry, ApiHolder, AlertDisplay, + OAuthRequestDialog, } from '@backstage/core'; import * as defaultApiFactories from './apiFactories'; @@ -90,6 +91,7 @@ class DevAppBuilder { return ( + {this.rootChildren} From 0f41ac4bf7667854f4bd0c2b45b1e71e329b80d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 1 Jun 2020 09:01:32 +0200 Subject: [PATCH 06/31] Add the MockedMemberFunctions helper --- packages/backend-common/src/index.ts | 1 + .../src/testing/MockedMemberFunctions.ts | 35 +++++++++++++++++++ packages/backend-common/src/testing/index.ts | 17 +++++++++ .../catalog/DatabaseEntitiesCatalog.test.ts | 35 ++++++++++++------- 4 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 packages/backend-common/src/testing/MockedMemberFunctions.ts create mode 100644 packages/backend-common/src/testing/index.ts diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts index b2c38ab506..4bc60f557f 100644 --- a/packages/backend-common/src/index.ts +++ b/packages/backend-common/src/index.ts @@ -17,3 +17,4 @@ export * from './errors'; export * from './logging'; export * from './middleware'; +export * from './testing'; diff --git a/packages/backend-common/src/testing/MockedMemberFunctions.ts b/packages/backend-common/src/testing/MockedMemberFunctions.ts new file mode 100644 index 0000000000..9b35908bff --- /dev/null +++ b/packages/backend-common/src/testing/MockedMemberFunctions.ts @@ -0,0 +1,35 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * For any type T, generate a new type that is identical but also has the + * jest.fn signature on all member functions. + * + * When writing tests against a type, you sometimes end up in a situation where + * you need to write expect(x.y as jest.Mock).toHaveBeenCalled... because the + * x.y member was considered to be the actual function type. You could also + * change your test to instead create a "raw" object { y: jest.fn() } but then + * you lose type safety when doing x.y.mockReturnValue(...). So you start + * trying to do { y: jest.fn() as X['y'] } as X or similar trickery. + * + * This type lets you say const x: MockedMemberFunctions = { y: jest.fn() } + * and keep all the type safety at every step. + */ +export type MockedMemberFunctions = { + [K in keyof T]: T[K] extends (...args: infer A) => infer B + ? T[K] & jest.Mock + : T[K]; +}; diff --git a/packages/backend-common/src/testing/index.ts b/packages/backend-common/src/testing/index.ts new file mode 100644 index 0000000000..c12297465b --- /dev/null +++ b/packages/backend-common/src/testing/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { MockedMemberFunctions } from './MockedMemberFunctions'; diff --git a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts index d897584c95..c5101dff7a 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts @@ -14,20 +14,31 @@ * limitations under the License. */ +import type { MockedMemberFunctions } from '@backstage/backend-common'; import type { Entity, EntityPolicy } from '@backstage/catalog-model'; import type { Database } from '../database'; import { DatabaseEntitiesCatalog } from './DatabaseEntitiesCatalog'; describe('DatabaseEntitiesCatalog', () => { - let db: Database; + let db: MockedMemberFunctions; let policy: EntityPolicy; beforeEach(() => { - // Since the database has a large API surface, we just leave it empty and - // let the tests insert whatever methods they need to call - db = ({ - transaction: jest.fn(async f => f('mock_tx')), - } as unknown) as Database; + db = { + transaction: jest.fn(), + addEntity: jest.fn(), + updateEntity: jest.fn(), + entities: jest.fn(), + entity: jest.fn(), + removeEntity: jest.fn(), + addLocation: jest.fn(), + removeLocation: jest.fn(), + location: jest.fn(), + locations: jest.fn(), + locationHistory: jest.fn(), + addLocationUpdateLogEvent: jest.fn(), + }; + db.transaction.mockImplementation(async f => f('tx')); policy = { enforce: jest.fn(async x => x) }; }); @@ -42,8 +53,8 @@ describe('DatabaseEntitiesCatalog', () => { }, }; - db.entities = jest.fn().mockResolvedValue([]); - db.addEntity = jest.fn().mockResolvedValue({ entity }); + db.entities.mockResolvedValue([]); + db.addEntity.mockResolvedValue({ entity }); const catalog = new DatabaseEntitiesCatalog(db, policy); const result = await catalog.addOrUpdateEntity(entity); @@ -65,8 +76,8 @@ describe('DatabaseEntitiesCatalog', () => { }, }; - db.entities = jest.fn().mockResolvedValue([]); - db.updateEntity = jest.fn().mockResolvedValue({ entity }); + db.entities.mockResolvedValue([]); + db.updateEntity.mockResolvedValue({ entity }); const catalog = new DatabaseEntitiesCatalog(db, policy); const result = await catalog.addOrUpdateEntity(entity); @@ -95,8 +106,8 @@ describe('DatabaseEntitiesCatalog', () => { }, }; - db.entities = jest.fn().mockResolvedValue([{ entity: existing }]); - db.updateEntity = jest.fn().mockResolvedValue({ entity: added }); + db.entities.mockResolvedValue([{ entity: existing }]); + db.updateEntity.mockResolvedValue({ entity: added }); const catalog = new DatabaseEntitiesCatalog(db, policy); const result = await catalog.addOrUpdateEntity(added); From 63221f6fc5a45f7f7e07022b950cd963b92e2e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20=C3=85lund?= Date: Mon, 1 Jun 2020 10:58:23 +0200 Subject: [PATCH 07/31] Fix incorrect markdown links (#1088) --- packages/catalog-model/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/catalog-model/README.md b/packages/catalog-model/README.md index 755b9ee63c..6dab6e7cae 100644 --- a/packages/catalog-model/README.md +++ b/packages/catalog-model/README.md @@ -7,6 +7,6 @@ as well as by others that want to consume catalog data. ## Links -- (Default frontend part of the catalog)[https://github.com/spotify/backstage/tree/master/plugins/catalog] -- (Default backend part of the catalog)[https://github.com/spotify/backstage/tree/master/plugins/catalog-backend] -- (The Backstage homepage)[https://backstage.io] +- [Default frontend part of the catalog](https://github.com/spotify/backstage/tree/master/plugins/catalog) +- [Default backend part of the catalog](https://github.com/spotify/backstage/tree/master/plugins/catalog-backend) +- [The Backstage homepage](https://backstage.io) From 438bdba2cf09dacd9a95bc0a82597b5e0841a7ac Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Mon, 1 Jun 2020 12:07:58 +0200 Subject: [PATCH 08/31] Use StaticAuthSessionManager for Github --- .../implementations/auth/github/GithubAuth.ts | 27 +++++-------- .../src/lib/AuthSessionManager/index.ts | 1 + .../src/providers/github/provider.ts | 39 ++++--------------- 3 files changed, 18 insertions(+), 49 deletions(-) diff --git a/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts index d20eaa54cb..d75bceef97 100644 --- a/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.ts @@ -20,7 +20,7 @@ import { GithubSession } from './types'; import { OAuthApi, AccessTokenOptions } from '../../../definitions/auth'; import { OAuthRequestApi, AuthProvider } from '../../../definitions'; import { SessionManager } from '../../../../lib/AuthSessionManager/types'; -import { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager'; +import { StaticAuthSessionManager } from '../../../../lib/AuthSessionManager'; type CreateOptions = { // TODO(Rugvip): These two should be grabbed from global config when available, they're not unique to GithubAuth @@ -63,20 +63,16 @@ class GithubAuth implements OAuthApi { sessionTransform(res: GithubAuthResponse): GithubSession { return { accessToken: res.accessToken, - scopes: GithubAuth.normalizeScopes(res.scope), + scopes: GithubAuth.normalizeScope(res.scope), expiresAt: new Date(Date.now() + res.expiresInSeconds * 1000), }; }, }); - const sessionManager = new RefreshingAuthSessionManager({ + const sessionManager = new StaticAuthSessionManager({ connector, defaultScopes: new Set(['user']), sessionScopes: session => session.scopes, - sessionShouldRefresh: session => { - const expiresInSec = (session.expiresAt.getTime() - Date.now()) / 1000; - return expiresInSec < 60 * 5; - }, }); return new GithubAuth(sessionManager); @@ -84,11 +80,8 @@ class GithubAuth implements OAuthApi { constructor(private readonly sessionManager: SessionManager) {} - async getAccessToken( - scope?: string | string[], - options?: AccessTokenOptions, - ) { - const normalizedScopes = GithubAuth.normalizeScopes(scope); + async getAccessToken(scope?: string, options?: AccessTokenOptions) { + const normalizedScopes = GithubAuth.normalizeScope(scope); const session = await this.sessionManager.getSession({ ...options, scopes: normalizedScopes, @@ -103,14 +96,14 @@ class GithubAuth implements OAuthApi { await this.sessionManager.removeSession(); } - static normalizeScopes(scopes?: string | string[]): Set { - if (!scopes) { + static normalizeScope(scope?: string): Set { + if (!scope) { return new Set(); } - const scopeList = Array.isArray(scopes) - ? scopes - : scopes.split(/[\s]/).filter(Boolean); + const scopeList = Array.isArray(scope) + ? scope + : scope.split(/[\s|,]/).filter(Boolean); return new Set(scopeList); } diff --git a/packages/core-api/src/lib/AuthSessionManager/index.ts b/packages/core-api/src/lib/AuthSessionManager/index.ts index 426c514646..16a8d3c378 100644 --- a/packages/core-api/src/lib/AuthSessionManager/index.ts +++ b/packages/core-api/src/lib/AuthSessionManager/index.ts @@ -15,4 +15,5 @@ */ export { RefreshingAuthSessionManager } from './RefreshingAuthSessionManager'; +export { StaticAuthSessionManager } from './StaticAuthSessionManager'; export * from './types'; diff --git a/plugins/auth-backend/src/providers/github/provider.ts b/plugins/auth-backend/src/providers/github/provider.ts index 1e8022e1cc..4445e98451 100644 --- a/plugins/auth-backend/src/providers/github/provider.ts +++ b/plugins/auth-backend/src/providers/github/provider.ts @@ -19,7 +19,6 @@ import { Strategy as GithubStrategy } from 'passport-github2'; import { executeFrameHandlerStrategy, executeRedirectStrategy, - executeRefreshTokenStrategy, } from '../PassportStrategyHelper'; import { OAuthProviderHandlers, @@ -37,23 +36,13 @@ export class GithubAuthProvider implements OAuthProviderHandlers { this.providerConfig = providerConfig; this._strategy = new GithubStrategy( { ...this.providerConfig.options }, - ( - accessToken: any, - refreshToken: any, - params: any, - profile: any, - done: any, - ) => { - done( - undefined, - { - profile, - accessToken, - scope: 'user', // params.scope is an empty string here for some reason, so hardcoding for now - expiresInSeconds: params.expires_in, - }, - { refreshToken }, - ); + (accessToken: any, _: any, params: any, profile: any, done: any) => { + done(undefined, { + profile, + accessToken, + scope: params.scope, + expiresInSeconds: params.expires_in, + }); }, ); } @@ -67,18 +56,4 @@ export class GithubAuthProvider implements OAuthProviderHandlers { ): Promise<{ user: AuthInfoBase; info: AuthInfoPrivate }> { return await executeFrameHandlerStrategy(req, this._strategy); } - - async refresh(refreshToken: string, scope: string): Promise { - const { accessToken, params } = await executeRefreshTokenStrategy( - this._strategy, - refreshToken, - scope, - ); - - return { - accessToken, - expiresInSeconds: params.expires_in, - scope: params.scope, - }; - } } From 86930c9dd2061381567c5b14564ae4e75ba6bb80 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Mon, 1 Jun 2020 12:09:05 +0200 Subject: [PATCH 09/31] Support providers without refresh tokens --- .../src/providers/OAuthProvider.ts | 36 +++++++++++++------ plugins/auth-backend/src/providers/config.ts | 1 + .../auth-backend/src/providers/factories.ts | 20 +++++++++-- plugins/auth-backend/src/providers/index.ts | 6 +--- plugins/auth-backend/src/providers/types.ts | 3 +- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/plugins/auth-backend/src/providers/OAuthProvider.ts b/plugins/auth-backend/src/providers/OAuthProvider.ts index 81f5ed25a6..30fd60f51f 100644 --- a/plugins/auth-backend/src/providers/OAuthProvider.ts +++ b/plugins/auth-backend/src/providers/OAuthProvider.ts @@ -89,9 +89,15 @@ export const removeRefreshTokenCookie = ( export class OAuthProvider implements AuthProviderRouteHandlers { private readonly provider: string; private readonly providerHandlers: OAuthProviderHandlers; - constructor(providerHandlers: OAuthProviderHandlers, provider: string) { + private readonly disableRefresh: boolean; + constructor( + providerHandlers: OAuthProviderHandlers, + provider: string, + disableRefresh?: boolean, + ) { this.provider = provider; this.providerHandlers = providerHandlers; + this.disableRefresh = disableRefresh ?? false; } async start(req: express.Request, res: express.Response): Promise { @@ -129,14 +135,16 @@ export class OAuthProvider implements AuthProviderRouteHandlers { const { user, info } = await this.providerHandlers.handler(req); - // throw error if missing refresh token - const { refreshToken } = info; - if (!refreshToken) { - throw new Error('Missing refresh token'); - } + if (!this.disableRefresh) { + // throw error if missing refresh token + const { refreshToken } = info; + if (!refreshToken) { + throw new Error('Missing refresh token'); + } - // set new refresh token - setRefreshTokenCookie(res, this.provider, refreshToken); + // set new refresh token + setRefreshTokenCookie(res, this.provider, refreshToken); + } // post message back to popup if successful return postMessageResponse(res, { @@ -160,8 +168,10 @@ export class OAuthProvider implements AuthProviderRouteHandlers { return res.status(401).send('Invalid X-Requested-With header'); } - // remove refresh token cookie before logout - removeRefreshTokenCookie(res, this.provider); + if (!this.disableRefresh) { + // remove refresh token cookie before logout + removeRefreshTokenCookie(res, this.provider); + } return res.send('logout!'); } @@ -170,6 +180,12 @@ export class OAuthProvider implements AuthProviderRouteHandlers { return res.status(401).send('Invalid X-Requested-With header'); } + if (!this.providerHandlers.refresh || this.disableRefresh) { + return res.send( + `Refresh token not supported for provider: ${this.provider}`, + ); + } + try { const refreshToken = req.cookies[`${this.provider}-refresh-token`]; diff --git a/plugins/auth-backend/src/providers/config.ts b/plugins/auth-backend/src/providers/config.ts index dad87e0448..8d04dc5a1f 100644 --- a/plugins/auth-backend/src/providers/config.ts +++ b/plugins/auth-backend/src/providers/config.ts @@ -30,5 +30,6 @@ export const providers = [ clientSecret: process.env.AUTH_GITHUB_CLIENT_SECRET!, callbackURL: 'http://localhost:7000/auth/github/handler/frame', }, + disableRefresh: true, }, ]; diff --git a/plugins/auth-backend/src/providers/factories.ts b/plugins/auth-backend/src/providers/factories.ts index 10e4153714..0c9f99e878 100644 --- a/plugins/auth-backend/src/providers/factories.ts +++ b/plugins/auth-backend/src/providers/factories.ts @@ -14,9 +14,14 @@ * limitations under the License. */ -import { AuthProviderFactories, AuthProviderFactory } from './types'; +import { + AuthProviderFactories, + AuthProviderRouteHandlers, + AuthProviderConfig, +} from './types'; import { GoogleAuthProvider } from './google'; import { GithubAuthProvider } from './github'; +import { OAuthProvider } from './OAuthProvider'; export class ProviderFactories { private static readonly providerFactories: AuthProviderFactories = { @@ -24,13 +29,22 @@ export class ProviderFactories { github: GithubAuthProvider, }; - public static getProviderFactory(providerId: string): AuthProviderFactory { + public static getProviderFactory( + config: AuthProviderConfig, + ): AuthProviderRouteHandlers { + const providerId = config.provider; const ProviderImpl = ProviderFactories.providerFactories[providerId]; if (!ProviderImpl) { throw Error( `Provider Implementation missing for : ${providerId} auth provider`, ); } - return ProviderImpl; + const providerInstance = new ProviderImpl(config); + const oauthProvider = new OAuthProvider( + providerInstance, + providerId, + config.disableRefresh, + ); + return oauthProvider; } } diff --git a/plugins/auth-backend/src/providers/index.ts b/plugins/auth-backend/src/providers/index.ts index 59dd116fa6..cfbabbbad1 100644 --- a/plugins/auth-backend/src/providers/index.ts +++ b/plugins/auth-backend/src/providers/index.ts @@ -17,7 +17,6 @@ import Router from 'express-promise-router'; import { AuthProviderRouteHandlers, AuthProviderConfig } from './types'; import { ProviderFactories } from './factories'; -import { OAuthProvider } from './OAuthProvider'; export const defaultRouter = (provider: AuthProviderRouteHandlers) => { const router = Router(); @@ -32,10 +31,7 @@ export const defaultRouter = (provider: AuthProviderRouteHandlers) => { export const makeProvider = (config: AuthProviderConfig) => { const providerId = config.provider; - const ProviderImpl = ProviderFactories.getProviderFactory(providerId); - const providerInstance = new ProviderImpl(config); - - const oauthProvider = new OAuthProvider(providerInstance, providerId); + const oauthProvider = ProviderFactories.getProviderFactory(config); const providerRouter = defaultRouter(oauthProvider); return { providerId, providerRouter }; }; diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index dcbe6ad1de..dc83c19dd0 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -20,12 +20,13 @@ import passport from 'passport'; export type AuthProviderConfig = { provider: string; options: any; + disableRefresh?: boolean; }; export interface OAuthProviderHandlers { start(req: express.Request, options: any): Promise; handler(req: express.Request): Promise; - refresh(refreshToken: string, scope: string): Promise; + refresh?(refreshToken: string, scope: string): Promise; logout?(): Promise; } From 25a4d6ed6b62db15e8ee80ffb3cd3d152fec7c9d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 1 Jun 2020 12:07:47 +0200 Subject: [PATCH 10/31] scripts: added check-type-dependencies --- scripts/.eslintrc.js | 6 + scripts/check-type-dependencies.js | 194 +++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 scripts/.eslintrc.js create mode 100755 scripts/check-type-dependencies.js diff --git a/scripts/.eslintrc.js b/scripts/.eslintrc.js new file mode 100644 index 0000000000..106fa4246a --- /dev/null +++ b/scripts/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], + rules: { + 'no-console': 0, + }, +}; diff --git a/scripts/check-type-dependencies.js b/scripts/check-type-dependencies.js new file mode 100755 index 0000000000..5b7daa13d2 --- /dev/null +++ b/scripts/check-type-dependencies.js @@ -0,0 +1,194 @@ +#!/usr/bin/env node +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const fs = require('fs'); +const { resolve: resolvePath } = require('path'); +// Cba polluting root package.json, we'll have this +// eslint-disable-next-line import/no-extraneous-dependencies +const chalk = require('chalk'); + +async function main() { + // This is from lerna, and cba polluting root package.json + // eslint-disable-next-line import/no-extraneous-dependencies + const LernaProject = require('@lerna/project'); + const project = new LernaProject(resolvePath('.')); + const packages = await project.getPackages(); + + let hadErrors = false; + + for (const pkg of packages) { + if (!shouldCheckTypes(pkg)) { + continue; + } + const { errors } = await checkTypes(pkg); + if (errors.length) { + hadErrors = true; + console.error( + `Incorrect type dependencies in ${chalk.yellow(pkg.name)}:`, + ); + for (const error of errors) { + if (error.name === 'WrongDepError') { + console.error( + ` Move from ${chalk.red(error.from)} to ${chalk.green( + error.to, + )}: ${chalk.cyan(error.dep)}`, + ); + } else if (error.name === 'MissingDepError') { + console.error( + ` Missing a type dependency: ${chalk.cyan(error.dep)}`, + ); + } else { + console.error(` Unknown error, ${chalk.red(error)}`); + } + } + } + } + + if (hadErrors) { + console.error(); + console.error( + chalk.red('At least one package had incorrect type dependencies'), + ); + + process.exit(2); + } +} + +function shouldCheckTypes(pkg) { + return !pkg.private && pkg.get('types'); +} + +/** + * Scan index.d.ts for imports and return errors for any dependency that's + * missing or incorrect in package.json + */ +function checkTypes(pkg) { + const typeDecl = fs.readFileSync( + resolvePath(pkg.location, 'dist/index.d.ts'), + 'utf8', + ); + const deps = (typeDecl.match(/from '.*'/g) || []) + .map(match => match.replace(/from '(.*)'/, '$1')) + .filter(n => !n.startsWith('.')); + + const errors = []; + const typeDeps = []; + for (const dep of deps) { + try { + const typeDep = findTypesPackage(dep, pkg); + if (typeDep) { + typeDeps.push(typeDep); + } + } catch (error) { + errors.push(error); + } + } + + errors.push(...findTypeDepErrors(typeDeps, pkg)); + + return { errors }; +} + +/** + * Find the package used for types. This assumes that types are working is a package + * can be resolved, it doesn't do any checking of presence of types inside the dep. + */ +function findTypesPackage(dep, pkg) { + try { + require.resolve(`@types/${dep}/package.json`, { paths: [pkg.location] }); + return `@types/${dep}`; + } catch { + try { + require.resolve(dep, { paths: [pkg.location] }); + return undefined; + } catch { + try { + // Some type-only modules don't have a working main field, so try resolving package.json too + require.resolve(`${dep}/package.json`, { paths: [pkg.location] }); + return undefined; + } catch { + try { + // Finally check if it's just a .d.ts file + require.resolve(`${dep}.d.ts`, { paths: [pkg.location] }); + return undefined; + } catch { + throw mkErr('MissingDepError', `No types for ${dep}`, { dep }); + } + } + } + } +} + +/** + * Figures out what type dependencies are missing, or should be moved between dep types + */ +function findTypeDepErrors(typeDeps, pkg) { + const devDeps = mkTypeDepSet(pkg.get('devDependencies')); + const deps = mkTypeDepSet(pkg.get('dependencies')); + + const errors = []; + for (const typeDep of typeDeps) { + if (!deps.has(typeDep)) { + if (devDeps.has(typeDep)) { + errors.push( + mkErr('WrongDepError', `Should be dep ${typeDep}`, { + dep: typeDep, + from: 'devDependencies', + to: 'dependencies', + }), + ); + } else { + errors.push( + mkErr('MissingDepError', `No types for ${typeDep}`, { + dep: typeDep, + }), + ); + } + } else { + deps.delete(typeDep); + } + } + + for (const dep of deps) { + errors.push( + mkErr('WrongDepError', `Should be dev dep ${dep}`, { + dep, + from: 'dependencies', + to: 'devDependencies', + }), + ); + } + + return errors; +} + +function mkTypeDepSet(deps) { + const typeDeps = Object.keys(deps || {}).filter(n => n.startsWith('@types/')); + return new Set(typeDeps); +} + +function mkErr(name, msg, extra) { + const error = new Error(msg); + error.name = name; + Object.assign(error, extra); + return error; +} + +main().catch(error => { + console.error(error.stack || error); + process.exit(1); +}); From c6abe12e45507621202de1123caa9b84eec41d16 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 1 Jun 2020 12:27:29 +0200 Subject: [PATCH 11/31] packages,plugins: fix incorrect type dependencies --- packages/core-api/package.json | 7 ++++--- packages/core-api/src/routing/index.ts | 1 + packages/core/package.json | 13 +++++++------ packages/dev-utils/package.json | 7 +++++-- packages/test-utils-core/package.json | 7 +++++-- packages/test-utils/package.json | 7 +++++-- plugins/tech-radar/package.json | 1 + yarn.lock | 2 +- 8 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/core-api/package.json b/packages/core-api/package.json index 73e7a18d33..a8c2b939ac 100644 --- a/packages/core-api/package.json +++ b/packages/core-api/package.json @@ -31,9 +31,7 @@ "@backstage/theme": "^0.1.1-alpha.6", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", - "@types/jest": "^25.2.2", - "@types/node": "^12.0.0", - "@types/zen-observable": "^0.8.0", + "@types/react": "^16.9", "prop-types": "^15.7.2", "react": "^16.12.0", "react-router-dom": "^5.2.0", @@ -46,6 +44,9 @@ "@testing-library/jest-dom": "^5.7.0", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^10.2.4", + "@types/jest": "^25.2.2", + "@types/node": "^12.0.0", + "@types/zen-observable": "^0.8.0", "jest-fetch-mock": "^3.0.3" }, "files": [ diff --git a/packages/core-api/src/routing/index.ts b/packages/core-api/src/routing/index.ts index 98e4f46d98..67d4c82167 100644 --- a/packages/core-api/src/routing/index.ts +++ b/packages/core-api/src/routing/index.ts @@ -16,3 +16,4 @@ export * from './types'; export { createRouteRef } from './RouteRef'; +export type { MutableRouteRef } from './RouteRef'; diff --git a/packages/core/package.json b/packages/core/package.json index a89ffc0b92..452633a4e5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -33,13 +33,8 @@ "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", - "@types/classnames": "^2.2.9", - "@types/google-protobuf": "^3.7.2", - "@types/jest": "^25.2.2", - "@types/node": "^12.0.0", - "@types/react-helmet": "^5.0.15", + "@types/react": "^16.9", "@types/react-sparklines": "^1.7.0", - "@types/zen-observable": "^0.8.0", "classnames": "^2.2.6", "clsx": "^1.1.0", "lodash": "^4.17.15", @@ -61,6 +56,12 @@ "@testing-library/jest-dom": "^5.7.0", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^10.2.4", + "@types/classnames": "^2.2.9", + "@types/google-protobuf": "^3.7.2", + "@types/jest": "^25.2.2", + "@types/node": "^12.0.0", + "@types/react-helmet": "^5.0.15", + "@types/zen-observable": "^0.8.0", "jest-fetch-mock": "^3.0.3" }, "files": [ diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 8c4b960ebb..fc77298371 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -37,14 +37,17 @@ "@testing-library/jest-dom": "^5.7.0", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^10.2.4", - "@types/jest": "^25.2.2", - "@types/node": "^12.0.0", + "@types/react": "^16.9", "react": "^16.12.0", "react-dom": "^16.12.0", "react-hot-loader": "^4.12.21", "react-router": "^5.2.0", "react-router-dom": "^5.2.0" }, + "devDependencies": { + "@types/jest": "^25.2.2", + "@types/node": "^12.0.0" + }, "files": [ "dist/**/*.{js,d.ts}" ] diff --git a/packages/test-utils-core/package.json b/packages/test-utils-core/package.json index ad4bbc95c9..f629877a65 100644 --- a/packages/test-utils-core/package.json +++ b/packages/test-utils-core/package.json @@ -30,11 +30,14 @@ "dependencies": { "@testing-library/jest-dom": "^5.7.0", "@testing-library/react": "^9.3.2", - "@types/jest": "^25.2.2", - "@types/node": "^12.0.0", + "@types/react": "^16.9", "react": "^16.12.0", "react-dom": "^16.12.0" }, + "devDependencies": { + "@types/jest": "^25.2.2", + "@types/node": "^12.0.0" + }, "files": [ "dist/**/*.{js,d.ts}" ] diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index fd893f8c8c..4bb7305671 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -35,13 +35,16 @@ "@testing-library/jest-dom": "^5.7.0", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^10.2.4", - "@types/jest": "^25.2.2", - "@types/node": "^12.0.0", + "@types/react": "^16.9", "react": "^16.12.0", "react-dom": "^16.12.0", "react-router": "^5.2.0", "react-router-dom": "^5.2.0" }, + "devDependencies": { + "@types/jest": "^25.2.2", + "@types/node": "^12.0.0" + }, "files": [ "dist/**/*.{js,d.ts}" ] diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 3a9c75a3f7..22568f8b97 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -26,6 +26,7 @@ "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", + "@types/react": "^16.9", "color": "^3.1.2", "d3-force": "^2.0.1", "prop-types": "^15.7.2", diff --git a/yarn.lock b/yarn.lock index b115b0bf9f..80e3916f53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4417,7 +4417,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.8.19": +"@types/react@*", "@types/react@^16.8.19", "@types/react@^16.9": version "16.9.25" resolved "https://registry.npmjs.org/@types/react/-/react-16.9.25.tgz#6ae2159b40138c792058a23c3c04fd3db49e929e" integrity sha512-Dlj2V72cfYLPNscIG3/SMUOzhzj7GK3bpSrfefwt2YT9GLynvLCCZjbhyF6VsT0q0+aRACRX03TDJGb7cA0cqg== From 54ca975bc1aacfad23ad7aa92197d98d74d8a257 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 1 Jun 2020 12:35:40 +0200 Subject: [PATCH 12/31] package.json: add lint:type-deps script --- docs/getting-started/development-environment.md | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/getting-started/development-environment.md b/docs/getting-started/development-environment.md index 4dd2f7c9c7..489116fcc8 100644 --- a/docs/getting-started/development-environment.md +++ b/docs/getting-started/development-environment.md @@ -44,6 +44,7 @@ yarn build # Build published versions of packages, depends on tsc yarn lint # lint packages that have changed since later commit on origin/master yarn lint:all # lint all packages +yarn lint:type-deps # verify that @types/* dependencies are placed correctly in packages yarn test # test packages that have changed since later commit on origin/master yarn test:all # test all packages diff --git a/package.json b/package.json index de924894c7..437ce36c4b 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "test:all": "lerna run test -- --coverage", "lint": "lerna run lint --since origin/master --", "lint:all": "lerna run lint --", + "lint:type-deps": "node scripts/check-type-dependencies.js", "docker-build": "yarn bundle && docker build . -t spotify/backstage", "create-plugin": "backstage-cli create-plugin", "remove-plugin": "backstage-cli remove-plugin", From 7c820941a6769c2fc9663c2bb419bdb530f7f0d5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 1 Jun 2020 12:35:47 +0200 Subject: [PATCH 13/31] workflows: verify type dependencies --- .github/workflows/frontend.yml | 3 +++ .github/workflows/master.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index d916141588..55a594d55e 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -71,6 +71,9 @@ jobs: if: ${{ steps.yarn-lock.outcome == 'failure' }} run: yarn lerna -- run build + - name: verify type dependencies + run: yarn lint:type-deps + - name: test changed packages if: ${{ steps.yarn-lock.outcome == 'success' }} run: yarn lerna -- run test --since origin/master -- --coverage diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index a41f25c262..14619305cd 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -60,6 +60,9 @@ jobs: - name: build run: yarn build + - name: verify type dependencies + run: yarn lint:type-deps + - name: test run: yarn lerna -- run test -- --coverage From e32f5a49ffd7159ac841aee0c32f1dc91d1b05d1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 28 May 2020 19:04:55 +0200 Subject: [PATCH 14/31] packages/test-utils: do app wrapping with actual app + remove wrapInThemedTestApp --- .../CodeSnippet/CodeSnippet.test.tsx | 10 ++- .../CopyTextButton/CopyTextButton.test.tsx | 6 +- .../DismissableBanner.test.js | 4 +- .../HorizontalScrollGrid.test.jsx | 6 +- .../components/Lifecycle/Lifecycle.test.jsx | 12 ++-- .../ProgressBars/CircleProgress.test.jsx | 14 ++--- .../ProgressBars/ProgressCard.test.jsx | 16 ++--- .../components/TrendLine/TrendLine.test.tsx | 12 ++-- .../WarningPanel/WarningPanel.test.tsx | 8 +-- .../ContentHeader/ContentHeader.test.tsx | 10 ++- .../src/layout/ErrorPage/ErrorPage.test.tsx | 6 +- .../core/src/layout/Header/Header.test.tsx | 12 ++-- .../HeaderActionMenu.test.tsx | 12 ++-- .../layout/HeaderLabel/HeaderLabel.test.tsx | 14 ++--- packages/test-utils/package.json | 1 + .../src/testUtils/appWrappers.test.tsx | 2 +- .../test-utils/src/testUtils/appWrappers.tsx | 63 ++++++++++++++----- .../CatalogFilter/CatalogFilter.test.tsx | 10 +-- .../CatalogPage/CatalogPage.test.tsx | 4 +- .../CatalogTable/CatalogTable.test.tsx | 8 +-- .../ComponentPage/ComponentPage.test.tsx | 4 +- .../src/components/ExploreCard.test.js | 20 +++--- .../AuditList/AuditListTable.test.tsx | 35 ++++------- .../src/components/AuditList/index.test.tsx | 37 +++++------ .../src/components/AuditView/index.test.tsx | 20 +++--- .../src/components/CreateAudit/index.test.tsx | 28 ++++----- .../src/components/Intro/index.test.tsx | 10 +-- 27 files changed, 185 insertions(+), 199 deletions(-) diff --git a/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx b/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx index 0d0c34a3e6..c019b316fd 100644 --- a/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx +++ b/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import CodeSnippet from './CodeSnippet'; @@ -33,16 +33,14 @@ const minProps = { describe('', () => { it('renders text without exploding', () => { - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText(/"Hello"/)).toBeInTheDocument(); expect(getByText(/"World"/)).toBeInTheDocument(); }); it('renders without line numbers', () => { const { queryByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(queryByText('1')).not.toBeInTheDocument(); expect(queryByText('2')).not.toBeInTheDocument(); @@ -51,7 +49,7 @@ describe('', () => { it('renders with line numbers', () => { const { queryByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(queryByText(/1/)).toBeInTheDocument(); expect(queryByText(/2/)).toBeInTheDocument(); diff --git a/packages/core/src/components/CopyTextButton/CopyTextButton.test.tsx b/packages/core/src/components/CopyTextButton/CopyTextButton.test.tsx index e0f7271014..dd83cd318d 100644 --- a/packages/core/src/components/CopyTextButton/CopyTextButton.test.tsx +++ b/packages/core/src/components/CopyTextButton/CopyTextButton.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import CopyTextButton from './CopyTextButton'; import { ApiRegistry, @@ -57,7 +57,7 @@ const apiRegistry = ApiRegistry.from([ describe('', () => { it('renders without exploding', () => { const { getByDisplayValue } = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -69,7 +69,7 @@ describe('', () => { it('displays tooltip on click', async () => { document.execCommand = jest.fn(); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , diff --git a/packages/core/src/components/DismissableBanner/DismissableBanner.test.js b/packages/core/src/components/DismissableBanner/DismissableBanner.test.js index 485b6226d2..8981acf8af 100644 --- a/packages/core/src/components/DismissableBanner/DismissableBanner.test.js +++ b/packages/core/src/components/DismissableBanner/DismissableBanner.test.js @@ -16,7 +16,7 @@ import React from 'react'; // import { fireEvent, waitForElementToBeRemoved } from '@testing-library/react'; -import { renderWithEffects, wrapInThemedTestApp } from '@backstage/test-utils'; +import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; // import { createSetting } from 'shared/apis/settings'; import DismissableBanner from './DismissableBanner'; @@ -30,7 +30,7 @@ describe('', () => { */ const rendered = await renderWithEffects( - wrapInThemedTestApp( + wrapInTestApp( ', () => { it('renders without exploding', () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( item1 item2 @@ -69,7 +69,7 @@ describe('', () => { }; const rendered = await renderWithEffects( - wrapInThemedTestApp( + wrapInTestApp( item1 diff --git a/packages/core/src/components/Lifecycle/Lifecycle.test.jsx b/packages/core/src/components/Lifecycle/Lifecycle.test.jsx index db0d2736ed..ac3823d85c 100644 --- a/packages/core/src/components/Lifecycle/Lifecycle.test.jsx +++ b/packages/core/src/components/Lifecycle/Lifecycle.test.jsx @@ -16,29 +16,27 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import { Lifecycle } from './Lifecycle'; describe('', () => { it('renders Alpha with shorthand', async () => { - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText('α')).toBeInTheDocument(); }); it('renders Alpha without shorthand', async () => { - const { getByText } = render(wrapInThemedTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText('Alpha')).toBeInTheDocument(); }); it('renders Beta with shorthand', async () => { - const { getByText } = render(wrapInThemedTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText('β')).toBeInTheDocument(); }); it('renders Beta without shorthand', async () => { - const { getByText } = render(wrapInThemedTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText('Beta')).toBeInTheDocument(); }); }); diff --git a/packages/core/src/components/ProgressBars/CircleProgress.test.jsx b/packages/core/src/components/ProgressBars/CircleProgress.test.jsx index 4975e00cb8..b42559b7b7 100644 --- a/packages/core/src/components/ProgressBars/CircleProgress.test.jsx +++ b/packages/core/src/components/ProgressBars/CircleProgress.test.jsx @@ -16,37 +16,33 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import CircleProgress, { getProgressColor } from './CircleProgress'; describe('', () => { it('renders without exploding', () => { const { getByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); getByText('10%'); }); it('handles fractional prop', () => { const { getByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); getByText('10%'); }); it('handles max prop', () => { const { getByText } = render( - wrapInThemedTestApp( - , - ), + wrapInTestApp(), ); getByText('1%'); }); it('handles unit prop', () => { const { getByText } = render( - wrapInThemedTestApp( - , - ), + wrapInTestApp(), ); getByText('10m'); }); diff --git a/packages/core/src/components/ProgressBars/ProgressCard.test.jsx b/packages/core/src/components/ProgressBars/ProgressCard.test.jsx index 7357cab812..3e93e3f302 100644 --- a/packages/core/src/components/ProgressBars/ProgressCard.test.jsx +++ b/packages/core/src/components/ProgressBars/ProgressCard.test.jsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import ProgressCard from './ProgressCard'; @@ -24,32 +24,26 @@ const minProps = { title: 'Tingle upgrade', progress: 0.12 }; describe('', () => { it('renders without exploding', () => { - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText(/Tingle.*/)).toBeInTheDocument(); }); it('renders progress and title', () => { - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText(/Tingle.*/)).toBeInTheDocument(); expect(getByText(/12%.*/)).toBeInTheDocument(); }); it('does not render deepLink', () => { const { queryByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(queryByText('View more')).not.toBeInTheDocument(); }); it('handles invalid numbers', () => { const badProps = { title: 'Tingle upgrade', progress: 'hejjo' }; - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText(/N\/A.*/)).toBeInTheDocument(); }); }); diff --git a/packages/core/src/components/TrendLine/TrendLine.test.tsx b/packages/core/src/components/TrendLine/TrendLine.test.tsx index 985e5d2b31..84e8413f01 100644 --- a/packages/core/src/components/TrendLine/TrendLine.test.tsx +++ b/packages/core/src/components/TrendLine/TrendLine.test.tsx @@ -17,7 +17,7 @@ /* eslint-disable jest/no-disabled-tests */ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import TrendLine from '.'; @@ -25,7 +25,7 @@ describe('TrendLine', () => { describe('when no data is present', () => { it('renders null without throwing', () => { const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(rendered.queryByTitle('sparkline')).not.toBeInTheDocument(); }); @@ -34,7 +34,7 @@ describe('TrendLine', () => { describe('when one datapoint is present', () => { it('renders as a straight line', () => { const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(rendered.getByTitle('sparkline')).toBeInTheDocument(); }); @@ -43,7 +43,7 @@ describe('TrendLine', () => { describe.skip('when the data finishes above the success threshold', () => { it('renders with the correct color', () => { const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(rendered.getByTitle('sparkline')).toBeInTheDocument(); }); @@ -52,7 +52,7 @@ describe('TrendLine', () => { describe.skip('when the data finishes within the the warning threshold', () => { it('renders with the correct color', () => { const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(rendered.getByTitle('sparkline')).toBeInTheDocument(); }); @@ -61,7 +61,7 @@ describe('TrendLine', () => { describe.skip('when the data finishes within the the error threshold', () => { it('renders with the correct color', () => { const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(rendered.getByTitle('sparkline')).toBeInTheDocument(); }); diff --git a/packages/core/src/components/WarningPanel/WarningPanel.test.tsx b/packages/core/src/components/WarningPanel/WarningPanel.test.tsx index 4094c65a1f..c4d836cfe1 100644 --- a/packages/core/src/components/WarningPanel/WarningPanel.test.tsx +++ b/packages/core/src/components/WarningPanel/WarningPanel.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import WarningPanel from './WarningPanel'; @@ -24,15 +24,13 @@ const minProps = { title: 'Mock title', message: 'Some more info' }; describe('', () => { it('renders without exploding', () => { - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText('Mock title')).toBeInTheDocument(); }); it('renders message and children', () => { const { getByText } = render( - wrapInThemedTestApp(children), + wrapInTestApp(children), ); expect(getByText('Some more info')).toBeInTheDocument(); expect(getByText('children')).toBeInTheDocument(); diff --git a/packages/core/src/layout/ContentHeader/ContentHeader.test.tsx b/packages/core/src/layout/ContentHeader/ContentHeader.test.tsx index 2f40511f35..5db676dcc5 100644 --- a/packages/core/src/layout/ContentHeader/ContentHeader.test.tsx +++ b/packages/core/src/layout/ContentHeader/ContentHeader.test.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { ContentHeader } from './ContentHeader'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; jest.mock('react-helmet', () => { return { @@ -27,9 +27,7 @@ jest.mock('react-helmet', () => { describe('', () => { it('should render with title', () => { - const rendered = render( - wrapInThemedTestApp(), - ); + const rendered = render(wrapInTestApp()); rendered.getByText('Title'); }); @@ -37,14 +35,14 @@ describe('', () => { const title = 'Custom title'; const titleComponent = () =>

{title}

; const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); rendered.getByText(title); }); it('should render with description', () => { const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); rendered.getByText('description'); }); diff --git a/packages/core/src/layout/ErrorPage/ErrorPage.test.tsx b/packages/core/src/layout/ErrorPage/ErrorPage.test.tsx index d383c3fbf0..c47ff8d49e 100644 --- a/packages/core/src/layout/ErrorPage/ErrorPage.test.tsx +++ b/packages/core/src/layout/ErrorPage/ErrorPage.test.tsx @@ -17,14 +17,12 @@ import React from 'react'; import { render } from '@testing-library/react'; import { ErrorPage } from './ErrorPage'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; describe('', () => { it('should render with status code, status message and go back link', () => { const rendered = render( - wrapInThemedTestApp( - , - ), + wrapInTestApp(), ); rendered.getByText(/page not found/i); rendered.getByText(/404/i); diff --git a/packages/core/src/layout/Header/Header.test.tsx b/packages/core/src/layout/Header/Header.test.tsx index c1f9be6cf6..5d28c6633f 100644 --- a/packages/core/src/layout/Header/Header.test.tsx +++ b/packages/core/src/layout/Header/Header.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import { Header } from './Header'; jest.mock('react-helmet', () => { @@ -27,19 +27,19 @@ jest.mock('react-helmet', () => { describe('
', () => { it('should render with title', () => { - const rendered = render(wrapInThemedTestApp(
)); + const rendered = render(wrapInTestApp(
)); rendered.getByText('Title'); }); it('should set document title', () => { - const rendered = render(wrapInThemedTestApp(
)); + const rendered = render(wrapInTestApp(
)); rendered.getByText('Title1'); rendered.getByText('defaultTitle: Title1 | Backstage'); }); it('should override document title', () => { const rendered = render( - wrapInThemedTestApp(
), + wrapInTestApp(
), ); rendered.getByText('Title1'); rendered.getByText('defaultTitle: Title2 | Backstage'); @@ -47,14 +47,14 @@ describe('
', () => { it('should have subtitle', () => { const rendered = render( - wrapInThemedTestApp(
), + wrapInTestApp(
), ); rendered.getByText('Subtitle'); }); it('should have type rendered', () => { const rendered = render( - wrapInThemedTestApp(
), + wrapInTestApp(
), ); rendered.getByText('tool'); }); diff --git a/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx b/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx index a1b5740f88..00fa4d27ac 100644 --- a/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx +++ b/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx @@ -16,18 +16,18 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; -import { wrapInThemedTestApp, Keyboard } from '@backstage/test-utils'; +import { wrapInTestApp, Keyboard } from '@backstage/test-utils'; import { HeaderActionMenu } from './HeaderActionMenu'; describe('', () => { it('renders without any items and without exploding', () => { - render(wrapInThemedTestApp()); + render(wrapInTestApp()); }); it('can open the menu and click menu items', () => { const onClickFunction = jest.fn(); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -49,7 +49,7 @@ describe('', () => { it('Disabled', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -66,7 +66,7 @@ describe('', () => { it('Test wrapper, and secondary label', () => { const onClickFunction = jest.fn(); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( ', () => { it('should close when hitting escape', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , ), ); diff --git a/packages/core/src/layout/HeaderLabel/HeaderLabel.test.tsx b/packages/core/src/layout/HeaderLabel/HeaderLabel.test.tsx index 11a22f9b5d..fdc6ef8c6e 100644 --- a/packages/core/src/layout/HeaderLabel/HeaderLabel.test.tsx +++ b/packages/core/src/layout/HeaderLabel/HeaderLabel.test.tsx @@ -16,39 +16,37 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import { HeaderLabel } from './HeaderLabel'; describe('', () => { it('should have a label', () => { - const rendered = render(wrapInThemedTestApp()); + const rendered = render(wrapInTestApp()); expect(rendered.getByText('Label')).toBeInTheDocument(); }); it('should say unknown', () => { - const rendered = render(wrapInThemedTestApp()); + const rendered = render(wrapInTestApp()); expect(rendered.getByText('')).toBeInTheDocument(); }); it('should say unknown when passing null as value prop', () => { const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(rendered.getByText('')).toBeInTheDocument(); }); it('should have value', () => { const rendered = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(rendered.getByText('Value')).toBeInTheDocument(); }); it('should have a link', () => { const rendered = render( - wrapInThemedTestApp( - , - ), + wrapInTestApp(), ); const anchor = rendered.container.querySelector('a') as HTMLAnchorElement; expect(rendered.getByText('Value')).toBeInTheDocument(); diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index fd893f8c8c..c35e3a622e 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "@backstage/cli": "^0.1.1-alpha.6", + "@backstage/core-api": "^0.1.1-alpha.6", "@backstage/test-utils-core": "^0.1.1-alpha.6", "@backstage/theme": "^0.1.1-alpha.6", "@material-ui/core": "^4.9.1", diff --git a/packages/test-utils/src/testUtils/appWrappers.test.tsx b/packages/test-utils/src/testUtils/appWrappers.test.tsx index e2f1b6b7cb..e46b6a95ce 100644 --- a/packages/test-utils/src/testUtils/appWrappers.test.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.test.tsx @@ -27,7 +27,7 @@ describe('wrapInTestApp', () => { Route 1 Route 2 , - ['/route2'], + { routeEntries: ['/route2'] }, ), ); expect(rendered.getByText('Route 2')).toBeInTheDocument(); diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index 06d8781669..c5839610d3 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -15,15 +15,52 @@ */ import React, { ComponentType, ReactNode, FunctionComponent } from 'react'; -import { ThemeProvider } from '@material-ui/core'; import { MemoryRouter } from 'react-router'; import { Route } from 'react-router-dom'; import { lightTheme } from '@backstage/theme'; +import privateExports, { + defaultSystemIcons, + ApiTestRegistry, +} from '@backstage/core-api'; +const { PrivateAppImpl } = privateExports; + +const NotFoundErrorPage = () => { + throw new Error('Reached NotFound Page'); +}; + +/** + * Options to customize the behavior of the test app wrapper. + */ +type TestAppOptions = { + /** + * Initial route entries to pass along as `initialEntries` to the router. + */ + routeEntries?: string[]; +}; export function wrapInTestApp( Component: ComponentType | ReactNode, - initialRouterEntries: string[] = ['/'], + options: TestAppOptions = {}, ) { + const { routeEntries = ['/'] } = options; + + const app = new PrivateAppImpl({ + apis: new ApiTestRegistry(), + components: { + NotFoundErrorPage, + }, + icons: defaultSystemIcons, + plugins: [], + themes: [ + { + id: 'light', + theme: lightTheme, + title: 'Test App Theme', + variant: 'light', + }, + ], + }); + let Wrapper: ComponentType; if (Component instanceof Function) { Wrapper = Component; @@ -31,21 +68,13 @@ export function wrapInTestApp( Wrapper = (() => Component) as FunctionComponent; } + const AppProvider = app.getProvider(); + return ( - - - + + + + + ); } - -export function wrapInThemedTestApp( - component: ReactNode, - initialRouterEntries: string[] = ['/'], -) { - const themed = {component}; - return wrapInTestApp(themed, initialRouterEntries); -} - -export const wrapInTheme = (component: ReactNode, theme = lightTheme) => ( - {component} -); diff --git a/plugins/catalog/src/components/CatalogFilter/CatalogFilter.test.tsx b/plugins/catalog/src/components/CatalogFilter/CatalogFilter.test.tsx index 762a881302..ec44f53777 100644 --- a/plugins/catalog/src/components/CatalogFilter/CatalogFilter.test.tsx +++ b/plugins/catalog/src/components/CatalogFilter/CatalogFilter.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import { CatalogFilter, CatalogFilterGroup } from './CatalogFilter'; describe('Catalog Filter', () => { @@ -26,7 +26,7 @@ describe('Catalog Filter', () => { { name: 'Test Group 2', items: [] }, ]; const { findByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); for (const group of mockGroups) { @@ -52,7 +52,7 @@ describe('Catalog Filter', () => { ]; const { findByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); const [group] = mockGroups; @@ -81,7 +81,7 @@ describe('Catalog Filter', () => { ]; const { findByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); const [group] = mockGroups; @@ -112,7 +112,7 @@ describe('Catalog Filter', () => { const onSelectedChangeHandler = jest.fn(); const { findByText } = render( - wrapInThemedTestApp( + wrapInTestApp( {} }; @@ -30,7 +30,7 @@ describe('CatalogPage', () => { // https://github.com/mbrn/material-table/issues/1293 it('should render', async () => { const rendered = render( - wrapInTheme( + wrapInTestApp( { it('should render loading when loading prop it set to true', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , ), ); @@ -38,7 +38,7 @@ describe('CatalogTable component', () => { it('should render error message when error is passed in props', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( { it('should display component names when loading has finished and no error occurred', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( { @@ -38,7 +38,7 @@ describe('ComponentPage', () => { it('should redirect to component table page when name is not provided', async () => { const props = getTestProps(''); await render( - wrapInTheme( + wrapInTestApp( , diff --git a/plugins/explore/src/components/ExploreCard.test.js b/plugins/explore/src/components/ExploreCard.test.js index fde36b529d..45652015a5 100644 --- a/plugins/explore/src/components/ExploreCard.test.js +++ b/plugins/explore/src/components/ExploreCard.test.js @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import ExploreCard from './ExploreCard'; @@ -32,22 +32,18 @@ const minProps = { describe('', () => { it('renders without exploding', () => { - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText('Explore')).toBeInTheDocument(); }); it('renders props correctly', () => { - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText(minProps.card.title)).toBeInTheDocument(); expect(getByText(minProps.card.description)).toBeInTheDocument(); }); it('should link out', () => { - const rendered = render(wrapInThemedTestApp()); + const rendered = render(wrapInTestApp()); const anchor = rendered.container.querySelector('a'); expect(anchor.href).toBe(minProps.card.url); }); @@ -63,7 +59,7 @@ describe('', () => { }, }; const { getByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(getByText('Description missing')).toBeInTheDocument(); }); @@ -78,15 +74,13 @@ describe('', () => { }, }; const { queryByText } = render( - wrapInThemedTestApp(), + wrapInTestApp(), ); expect(queryByText('GA')).not.toBeInTheDocument(); }); it('renders tags correctly', () => { - const { getByText } = render( - wrapInThemedTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText(minProps.card.tags[0])).toBeInTheDocument(); expect(getByText(minProps.card.tags[1])).toBeInTheDocument(); }); diff --git a/plugins/lighthouse/src/components/AuditList/AuditListTable.test.tsx b/plugins/lighthouse/src/components/AuditList/AuditListTable.test.tsx index cebab93f17..039b397083 100644 --- a/plugins/lighthouse/src/components/AuditList/AuditListTable.test.tsx +++ b/plugins/lighthouse/src/components/AuditList/AuditListTable.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import { ApiRegistry, ApiProvider } from '@backstage/core'; import AuditListTable from './AuditListTable'; @@ -50,12 +50,10 @@ describe('AuditListTable', () => { ); }; it('renders the link to each website', () => { - const rendered = render( - wrapInThemedTestApp(auditList(websiteListResponse)), - ); + const rendered = render(wrapInTestApp(auditList(websiteListResponse))); const link = rendered.queryByText('https://anchor.fm'); const website = websiteListResponse.items.find( - (w) => w.url === 'https://anchor.fm', + w => w.url === 'https://anchor.fm', ); if (!website) throw new Error('https://anchor.fm must be present in fixture'); @@ -67,11 +65,9 @@ describe('AuditListTable', () => { }); it('renders the dates that are available for a given row', () => { - const rendered = render( - wrapInThemedTestApp(auditList(websiteListResponse)), - ); + const rendered = render(wrapInTestApp(auditList(websiteListResponse))); const website = websiteListResponse.items.find( - (w) => w.url === 'https://anchor.fm', + w => w.url === 'https://anchor.fm', ); if (!website) throw new Error('https://anchor.fm must be present in fixture'); @@ -81,35 +77,30 @@ describe('AuditListTable', () => { }); it('renders the status for a given row', async () => { - const rendered = render( - wrapInThemedTestApp(auditList(websiteListResponse)), - ); + const rendered = render(wrapInTestApp(auditList(websiteListResponse))); const completed = await rendered.findAllByText('COMPLETED'); expect(completed).toHaveLength( - websiteListResponse.items.filter( - (w) => w.lastAudit.status === 'COMPLETED', - ).length, + websiteListResponse.items.filter(w => w.lastAudit.status === 'COMPLETED') + .length, ); const failed = await rendered.findAllByText('FAILED'); expect(failed).toHaveLength( - websiteListResponse.items.filter((w) => w.lastAudit.status === 'FAILED') + websiteListResponse.items.filter(w => w.lastAudit.status === 'FAILED') .length, ); const running = await rendered.findAllByText('FAILED'); expect(running).toHaveLength( - websiteListResponse.items.filter((w) => w.lastAudit.status === 'RUNNING') + websiteListResponse.items.filter(w => w.lastAudit.status === 'RUNNING') .length, ); }); describe('sparklines', () => { it('correctly maps the data from the website payload', () => { - const rendered = render( - wrapInThemedTestApp(auditList(websiteListResponse)), - ); + const rendered = render(wrapInTestApp(auditList(websiteListResponse))); const backstageSEO = rendered.getByTitle( 'trendline for SEO category of https://backstage.io', ); @@ -117,9 +108,7 @@ describe('AuditListTable', () => { }); it('does not break when no data is available', () => { - const rendered = render( - wrapInThemedTestApp(auditList(websiteListResponse)), - ); + const rendered = render(wrapInTestApp(auditList(websiteListResponse))); const anchorSEO = rendered.queryByTitle( 'trendline for SEO category of https://anchor.fm', ); diff --git a/plugins/lighthouse/src/components/AuditList/index.test.tsx b/plugins/lighthouse/src/components/AuditList/index.test.tsx index 9bd6e98aaa..bcd486e876 100644 --- a/plugins/lighthouse/src/components/AuditList/index.test.tsx +++ b/plugins/lighthouse/src/components/AuditList/index.test.tsx @@ -27,11 +27,10 @@ jest.mock('react-router-dom', () => { }); import React from 'react'; -import { MemoryRouter } from 'react-router-dom'; import mockFetch from 'jest-fetch-mock'; import { render, fireEvent } from '@testing-library/react'; import { ApiRegistry, ApiProvider } from '@backstage/core'; -import { wrapInThemedTestApp, wrapInTheme } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import { lighthouseApiRef, @@ -57,7 +56,7 @@ describe('AuditList', () => { it('should render the table', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -69,7 +68,7 @@ describe('AuditList', () => { it('renders a link to create a new audit', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -87,12 +86,11 @@ describe('AuditList', () => { it('requests the correct limit and offset from the api based on the query', () => { mockFetch.mockClear(); render( - wrapInTheme( - - - - - , + wrapInTestApp( + + + , + { routeEntries: ['/lighthouse?page=2'] }, ), ); expect(mockFetch).toHaveBeenLastCalledWith( @@ -104,7 +102,7 @@ describe('AuditList', () => { describe('when only one page is needed', () => { it('hides pagination elements', () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -125,7 +123,7 @@ describe('AuditList', () => { it('shows pagination elements', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -138,12 +136,11 @@ describe('AuditList', () => { it('changes the page on click', async () => { const rendered = render( - wrapInTheme( - - - - - , + wrapInTestApp( + + + , + { routeEntries: ['/lighthouse?page=2'] }, ), ); const element = await rendered.findByLabelText(/Go to page 1/); @@ -157,7 +154,7 @@ describe('AuditList', () => { it('should render the loader', async () => { mockFetch.mockResponseOnce(() => new Promise(() => {})); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -172,7 +169,7 @@ describe('AuditList', () => { it('should render an error', async () => { mockFetch.mockRejectOnce(new Error('failed to fetch')); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , diff --git a/plugins/lighthouse/src/components/AuditView/index.test.tsx b/plugins/lighthouse/src/components/AuditView/index.test.tsx index 4e261fcf39..b2c15cd8b7 100644 --- a/plugins/lighthouse/src/components/AuditView/index.test.tsx +++ b/plugins/lighthouse/src/components/AuditView/index.test.tsx @@ -27,7 +27,7 @@ jest.mock('react-router-dom', () => { import React from 'react'; import mockFetch from 'jest-fetch-mock'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import { ApiRegistry, ApiProvider } from '@backstage/core'; import AuditView from '.'; @@ -56,7 +56,7 @@ describe('AuditView', () => { it('renders the iframe for the selected audit', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -72,7 +72,7 @@ describe('AuditView', () => { it('renders a link to create a new audit for this website', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -92,7 +92,7 @@ describe('AuditView', () => { describe('sidebar', () => { it('renders a list of all audits for the website', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -110,7 +110,7 @@ describe('AuditView', () => { it('sets the current audit as active', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -138,7 +138,7 @@ describe('AuditView', () => { it('navigates to the next report when an audit is clicked', async () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -160,7 +160,7 @@ describe('AuditView', () => { it('it shows the loading', async () => { mockFetch.mockImplementationOnce(() => new Promise(() => {})); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -174,7 +174,7 @@ describe('AuditView', () => { it('it shows an error', async () => { mockFetch.mockRejectOnce(new Error('failed to fetch')); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -191,7 +191,7 @@ describe('AuditView', () => { useParams.mockReturnValueOnce({ id }); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -211,7 +211,7 @@ describe('AuditView', () => { useParams.mockReturnValueOnce({ id }); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , diff --git a/plugins/lighthouse/src/components/CreateAudit/index.test.tsx b/plugins/lighthouse/src/components/CreateAudit/index.test.tsx index 79897539c4..08e8005530 100644 --- a/plugins/lighthouse/src/components/CreateAudit/index.test.tsx +++ b/plugins/lighthouse/src/components/CreateAudit/index.test.tsx @@ -29,14 +29,13 @@ jest.mock('react-router-dom', () => { import React from 'react'; import mockFetch from 'jest-fetch-mock'; import { wait, render, fireEvent } from '@testing-library/react'; -import { MemoryRouter } from 'react-router-dom'; import { ApiRegistry, ApiProvider, ErrorApi, errorApiRef, } from '@backstage/core'; -import { wrapInThemedTestApp, wrapInTheme } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import { lighthouseApiRef, LighthouseRestApi, Audit } from '../../api'; import CreateAudit from '.'; @@ -62,7 +61,7 @@ describe('CreateAudit', () => { it('renders the form', () => { const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -77,16 +76,15 @@ describe('CreateAudit', () => { it('prefills the url into the form', () => { const url = 'https://spotify.com'; const rendered = render( - wrapInTheme( - + + , + { + routeEntries: [ `/lighthouse/create-audit?url=${encodeURIComponent(url)}`, - ]} - > - - - - , + ], + }, ), ); expect(rendered.getByLabelText(/URL/)).toHaveAttribute('value', url); @@ -98,7 +96,7 @@ describe('CreateAudit', () => { mockFetch.mockResponseOnce(() => new Promise(() => {})); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -121,7 +119,7 @@ describe('CreateAudit', () => { mockFetch.mockResponseOnce(JSON.stringify(createAuditResponse)); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , @@ -152,7 +150,7 @@ describe('CreateAudit', () => { mockFetch.mockRejectOnce(new Error('failed to post')); const rendered = render( - wrapInThemedTestApp( + wrapInTestApp( , diff --git a/plugins/lighthouse/src/components/Intro/index.test.tsx b/plugins/lighthouse/src/components/Intro/index.test.tsx index e64e8114d3..183008dc3c 100644 --- a/plugins/lighthouse/src/components/Intro/index.test.tsx +++ b/plugins/lighthouse/src/components/Intro/index.test.tsx @@ -18,13 +18,13 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; -import { wrapInThemedTestApp } from '@backstage/test-utils'; +import { wrapInTestApp } from '@backstage/test-utils'; import LighthouseIntro from '.'; describe('LighthouseIntro', () => { it('renders successfully', () => { - const rendered = render(wrapInThemedTestApp()); + const rendered = render(wrapInTestApp()); expect( rendered.queryByText('Welcome to Lighthouse in Backstage!'), ).toBeInTheDocument(); @@ -35,13 +35,13 @@ describe('LighthouseIntro', () => { const secondTabRe = /you will need a running instance of/; it('selects the first text element', () => { - const rendered = render(wrapInThemedTestApp()); + const rendered = render(wrapInTestApp()); expect(rendered.queryByText(firstTabRe)).toBeInTheDocument(); expect(rendered.queryByText(secondTabRe)).not.toBeInTheDocument(); }); it('shows the other text when the tab is clicked', () => { - const rendered = render(wrapInThemedTestApp()); + const rendered = render(wrapInTestApp()); fireEvent.click(rendered.getByText('Setup')); expect(rendered.queryByText(firstTabRe)).not.toBeInTheDocument(); expect(rendered.queryByText(secondTabRe)).toBeInTheDocument(); @@ -50,7 +50,7 @@ describe('LighthouseIntro', () => { describe('closing', () => { it('hides the content on click', () => { - const rendered = render(wrapInThemedTestApp()); + const rendered = render(wrapInTestApp()); const welcomeMessage = rendered.queryByText( 'Welcome to Lighthouse in Backstage!', ); From 44f61015f5eb0a0cbfdfaf44e1b0a02f74b16b2b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 1 Jun 2020 14:01:05 +0200 Subject: [PATCH 15/31] packages/test-utils: add missing wrappapper props --- packages/test-utils/src/testUtils/appWrappers.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index c5839610d3..7849ed20cc 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -14,19 +14,24 @@ * limitations under the License. */ -import React, { ComponentType, ReactNode, FunctionComponent } from 'react'; +import React, { ComponentType, ReactNode, FunctionComponent, FC } from 'react'; import { MemoryRouter } from 'react-router'; import { Route } from 'react-router-dom'; import { lightTheme } from '@backstage/theme'; import privateExports, { defaultSystemIcons, ApiTestRegistry, + BootErrorPageProps, } from '@backstage/core-api'; const { PrivateAppImpl } = privateExports; const NotFoundErrorPage = () => { throw new Error('Reached NotFound Page'); }; +const BootErrorPage: FC = ({ step, error }) => { + throw new Error(`Reached BootError Page at step ${step} with error ${error}`); +}; +const Progress = () =>
; /** * Options to customize the behavior of the test app wrapper. @@ -48,6 +53,8 @@ export function wrapInTestApp( apis: new ApiTestRegistry(), components: { NotFoundErrorPage, + BootErrorPage, + Progress, }, icons: defaultSystemIcons, plugins: [], @@ -59,6 +66,7 @@ export function wrapInTestApp( variant: 'light', }, ], + configLoader: async () => ({}), }); let Wrapper: ComponentType; From 9c415c351fd4262afb3a82898309b3cb484f6d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20=C3=85lund?= Date: Mon, 1 Jun 2020 14:24:27 +0200 Subject: [PATCH 16/31] Add ADR link to README (#1069) * Add ADR link to README * Update README.md * rm extra line --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e22818f4b..c1ca77c2cc 100644 --- a/README.md +++ b/README.md @@ -82,12 +82,11 @@ Take a look at the [Getting Started](docs/getting-started/README.md) guide to le - [Getting Started](docs/getting-started/README.md) - [Create a Backstage App](docs/create-an-app.md) -- [Architecture](docs/architecture-terminology.md) +- [Architecture](docs/architecture-terminology.md) ([Decisions](docs/architecture-decisions)) - [API references](docs/reference/README.md) - [Designing for Backstage](docs/design.md) - [Storybook - UI components](http://storybook.backstage.io) - [Contributing to Storybook](docs/getting-started/contributing-to-storybook.md) -- Using Backstage components (TODO) ## Contributing From c2877e0a1acea51d27db2f9cb0121f0030077394 Mon Sep 17 00:00:00 2001 From: Raghunandan Date: Sun, 31 May 2020 14:50:59 +0200 Subject: [PATCH 17/31] Add PassportStrategyHelper tests. Move util fns to OAuthProvider class. --- .../src/providers/OAuthProvider.test.ts | 21 ++ .../src/providers/OAuthProvider.ts | 39 +++- .../providers/PassportStrategyHelper.test.ts | 214 ++++++++++++++++++ plugins/auth-backend/src/providers/utils.ts | 50 ---- 4 files changed, 272 insertions(+), 52 deletions(-) create mode 100644 plugins/auth-backend/src/providers/OAuthProvider.test.ts create mode 100644 plugins/auth-backend/src/providers/PassportStrategyHelper.test.ts delete mode 100644 plugins/auth-backend/src/providers/utils.ts diff --git a/plugins/auth-backend/src/providers/OAuthProvider.test.ts b/plugins/auth-backend/src/providers/OAuthProvider.test.ts new file mode 100644 index 0000000000..308849057b --- /dev/null +++ b/plugins/auth-backend/src/providers/OAuthProvider.test.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('OAuthProvider', () => { + it('unbreak test runner', () => { + expect(true).toBeTruthy(); + }); +}); diff --git a/plugins/auth-backend/src/providers/OAuthProvider.ts b/plugins/auth-backend/src/providers/OAuthProvider.ts index 81f5ed25a6..822cd5b267 100644 --- a/plugins/auth-backend/src/providers/OAuthProvider.ts +++ b/plugins/auth-backend/src/providers/OAuthProvider.ts @@ -16,9 +16,12 @@ import express, { CookieOptions } from 'express'; import crypto from 'crypto'; -import { AuthProviderRouteHandlers, OAuthProviderHandlers } from './types'; +import { + AuthResponse, + AuthProviderRouteHandlers, + OAuthProviderHandlers, +} from './types'; import { InputError } from '@backstage/backend-common'; -import { postMessageResponse, ensuresXRequestedWith } from './utils'; export const THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000; export const TEN_MINUTES_MS = 600 * 1000; @@ -86,6 +89,38 @@ export const removeRefreshTokenCookie = ( res.cookie(`${provider}-refresh-token`, '', options); }; +export const postMessageResponse = ( + res: express.Response, + data: AuthResponse, +) => { + const jsonData = JSON.stringify(data); + const base64Data = Buffer.from(jsonData, 'utf8').toString('base64'); + + res.setHeader('Content-Type', 'text/html'); + res.setHeader('X-Frame-Options', 'sameorigin'); + + // TODO: Make target app origin configurable globally + res.end(` + + + + + + `); +}; + +export const ensuresXRequestedWith = (req: express.Request) => { + const requiredHeader = req.header('X-Requested-With'); + + if (!requiredHeader || requiredHeader !== 'XMLHttpRequest') { + return false; + } + return true; +}; + export class OAuthProvider implements AuthProviderRouteHandlers { private readonly provider: string; private readonly providerHandlers: OAuthProviderHandlers; diff --git a/plugins/auth-backend/src/providers/PassportStrategyHelper.test.ts b/plugins/auth-backend/src/providers/PassportStrategyHelper.test.ts new file mode 100644 index 0000000000..e977ee877d --- /dev/null +++ b/plugins/auth-backend/src/providers/PassportStrategyHelper.test.ts @@ -0,0 +1,214 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import express from 'express'; +import passport from 'passport'; +import { + executeRedirectStrategy, + executeFrameHandlerStrategy, + executeRefreshTokenStrategy, +} from './PassportStrategyHelper'; + +const mockRequest = ({} as unknown) as express.Request; + +describe('PassportStrategyHelper', () => { + class MyCustomRedirectStrategy extends passport.Strategy { + authenticate() { + this.redirect('a', 302); + } + } + + describe('executeRedirectStrategy', () => { + it('should call authenticate and resolve with RedirectInfo', async () => { + const mockStrategy = new MyCustomRedirectStrategy(); + const spyAuthenticate = jest.spyOn(mockStrategy, 'authenticate'); + const redirectStrategyPromise = executeRedirectStrategy( + mockRequest, + mockStrategy, + {}, + ); + expect(spyAuthenticate).toBeCalledTimes(1); + await expect(redirectStrategyPromise).resolves.toStrictEqual( + expect.objectContaining({ url: 'a', status: 302 }), + ); + }); + }); + + describe('executeFrameHandlerStrategy', () => { + class MyCustomAuthSuccessStrategy extends passport.Strategy { + authenticate() { + this.success( + { accessToken: 'ACCESS_TOKEN' }, + { refreshToken: 'REFRESH_TOKEN' }, + ); + } + } + class MyCustomAuthErrorStrategy extends passport.Strategy { + authenticate() { + this.error(new Error('MyCustomAuth error')); + } + } + class MyCustomAuthRedirectStrategy extends passport.Strategy { + authenticate() { + this.redirect('URL', 302); + } + } + class MyCustomAuthFailStrategy extends passport.Strategy { + authenticate() { + this.fail('challenge', 302); + } + } + + it('should resolve with user and info on success', async () => { + const mockStrategy = new MyCustomAuthSuccessStrategy(); + const spyAuthenticate = jest.spyOn(mockStrategy, 'authenticate'); + const frameHandlerStrategyPromise = executeFrameHandlerStrategy( + mockRequest, + mockStrategy, + ); + expect(spyAuthenticate).toBeCalledTimes(1); + await expect(frameHandlerStrategyPromise).resolves.toStrictEqual( + expect.objectContaining({ + user: { accessToken: 'ACCESS_TOKEN' }, + info: { refreshToken: 'REFRESH_TOKEN' }, + }), + ); + }); + + it('should reject on error', async () => { + const mockStrategy = new MyCustomAuthErrorStrategy(); + const spyAuthenticate = jest.spyOn(mockStrategy, 'authenticate'); + const frameHandlerStrategyPromise = executeFrameHandlerStrategy( + mockRequest, + mockStrategy, + ); + expect(spyAuthenticate).toBeCalledTimes(1); + await expect(frameHandlerStrategyPromise).rejects.toThrow( + 'Authentication failed, Error: MyCustomAuth error', + ); + }); + + it('should reject on redirect', async () => { + const mockStrategy = new MyCustomAuthRedirectStrategy(); + const spyAuthenticate = jest.spyOn(mockStrategy, 'authenticate'); + const frameHandlerStrategyPromise = executeFrameHandlerStrategy( + mockRequest, + mockStrategy, + ); + expect(spyAuthenticate).toBeCalledTimes(1); + await expect(frameHandlerStrategyPromise).rejects.toThrow( + 'Unexpected redirect', + ); + }); + + it('should reject on fail', async () => { + const mockStrategy = new MyCustomAuthFailStrategy(); + const spyAuthenticate = jest.spyOn(mockStrategy, 'authenticate'); + const frameHandlerStrategyPromise = executeFrameHandlerStrategy( + mockRequest, + mockStrategy, + ); + expect(spyAuthenticate).toBeCalledTimes(1); + await expect(frameHandlerStrategyPromise).rejects.toThrow(); + }); + }); + + describe('executeRefreshTokenStrategy', () => { + it('should resolve with a new access token, scope and expiry', async () => { + class MyCustomOAuth2Success { + getOAuthAccessToken( + _refreshToken: string, + _options: any, + callback: Function, + ) { + callback(null, 'ACCESS_TOKEN', 'REFRESH_TOKEN', { + scope: 'a', + expires_in: 10, + }); + } + } + class MyCustomRefreshTokenSuccess extends passport.Strategy { + // @ts-ignore + private _oauth2 = new MyCustomOAuth2Success(); + } + + const mockStrategy = new MyCustomRefreshTokenSuccess(); + const refreshTokenPromise = executeRefreshTokenStrategy( + mockStrategy, + 'REFRESH_TOKEN', + 'a', + ); + await expect(refreshTokenPromise).resolves.toStrictEqual( + expect.objectContaining({ + accessToken: 'ACCESS_TOKEN', + params: expect.objectContaining({ scope: 'a', expires_in: 10 }), + }), + ); + }); + + it('should reject with an error if refresh failed', async () => { + class MyCustomOAuth2Error { + getOAuthAccessToken( + _refreshToken: string, + _options: any, + callback: Function, + ) { + callback(new Error('Unknown error')); + } + } + class MyCustomRefreshTokenSuccess extends passport.Strategy { + // @ts-ignore + private _oauth2 = new MyCustomOAuth2Error(); + } + + const mockStrategy = new MyCustomRefreshTokenSuccess(); + const refreshTokenPromise = executeRefreshTokenStrategy( + mockStrategy, + 'REFRESH_TOKEN', + 'a', + ); + await expect(refreshTokenPromise).rejects.toThrow( + 'Failed to refresh access token Error: Unknown error', + ); + }); + + it('should reject with an error if access token missing in refresh callback', async () => { + class MyCustomOAuth2AccessTokenMissing { + getOAuthAccessToken( + _refreshToken: string, + _options: any, + callback: Function, + ) { + callback(null, ''); + } + } + class MyCustomRefreshTokenSuccess extends passport.Strategy { + // @ts-ignore + private _oauth2 = new MyCustomOAuth2AccessTokenMissing(); + } + + const mockStrategy = new MyCustomRefreshTokenSuccess(); + const refreshTokenPromise = executeRefreshTokenStrategy( + mockStrategy, + 'REFRESH_TOKEN', + 'a', + ); + await expect(refreshTokenPromise).rejects.toThrow( + 'Failed to refresh access token, no access token received', + ); + }); + }); +}); diff --git a/plugins/auth-backend/src/providers/utils.ts b/plugins/auth-backend/src/providers/utils.ts deleted file mode 100644 index 83229e55d4..0000000000 --- a/plugins/auth-backend/src/providers/utils.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import express from 'express'; -import { AuthResponse } from './types'; - -export const postMessageResponse = ( - res: express.Response, - data: AuthResponse, -) => { - const jsonData = JSON.stringify(data); - const base64Data = Buffer.from(jsonData, 'utf8').toString('base64'); - - res.setHeader('Content-Type', 'text/html'); - res.setHeader('X-Frame-Options', 'sameorigin'); - - // TODO: Make target app origin configurable globally - res.end(` - - - - - - `); -}; - -export const ensuresXRequestedWith = (req: express.Request) => { - const requiredHeader = req.header('X-Requested-With'); - - if (!requiredHeader || requiredHeader !== 'XMLHttpRequest') { - return false; - } - return true; -}; From a90e6ab44ff3470d5bcbd7fe1ada2bfe7f21fafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 1 Jun 2020 14:47:09 +0200 Subject: [PATCH 18/31] Update plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts Co-authored-by: Patrik Oldsberg --- packages/backend-common/src/index.ts | 1 - .../src/testing/MockedMemberFunctions.ts | 35 ------------------- packages/backend-common/src/testing/index.ts | 17 --------- .../catalog/DatabaseEntitiesCatalog.test.ts | 3 +- 4 files changed, 1 insertion(+), 55 deletions(-) delete mode 100644 packages/backend-common/src/testing/MockedMemberFunctions.ts delete mode 100644 packages/backend-common/src/testing/index.ts diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts index 4bc60f557f..b2c38ab506 100644 --- a/packages/backend-common/src/index.ts +++ b/packages/backend-common/src/index.ts @@ -17,4 +17,3 @@ export * from './errors'; export * from './logging'; export * from './middleware'; -export * from './testing'; diff --git a/packages/backend-common/src/testing/MockedMemberFunctions.ts b/packages/backend-common/src/testing/MockedMemberFunctions.ts deleted file mode 100644 index 9b35908bff..0000000000 --- a/packages/backend-common/src/testing/MockedMemberFunctions.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * For any type T, generate a new type that is identical but also has the - * jest.fn signature on all member functions. - * - * When writing tests against a type, you sometimes end up in a situation where - * you need to write expect(x.y as jest.Mock).toHaveBeenCalled... because the - * x.y member was considered to be the actual function type. You could also - * change your test to instead create a "raw" object { y: jest.fn() } but then - * you lose type safety when doing x.y.mockReturnValue(...). So you start - * trying to do { y: jest.fn() as X['y'] } as X or similar trickery. - * - * This type lets you say const x: MockedMemberFunctions = { y: jest.fn() } - * and keep all the type safety at every step. - */ -export type MockedMemberFunctions = { - [K in keyof T]: T[K] extends (...args: infer A) => infer B - ? T[K] & jest.Mock - : T[K]; -}; diff --git a/packages/backend-common/src/testing/index.ts b/packages/backend-common/src/testing/index.ts deleted file mode 100644 index c12297465b..0000000000 --- a/packages/backend-common/src/testing/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export type { MockedMemberFunctions } from './MockedMemberFunctions'; diff --git a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts index c5101dff7a..1de5038112 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts @@ -14,13 +14,12 @@ * limitations under the License. */ -import type { MockedMemberFunctions } from '@backstage/backend-common'; import type { Entity, EntityPolicy } from '@backstage/catalog-model'; import type { Database } from '../database'; import { DatabaseEntitiesCatalog } from './DatabaseEntitiesCatalog'; describe('DatabaseEntitiesCatalog', () => { - let db: MockedMemberFunctions; + let db: jest.Mocked; let policy: EntityPolicy; beforeEach(() => { From 65ab1685f4d71dda10892902f545d79c27eb2a99 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 1 Jun 2020 14:58:52 +0200 Subject: [PATCH 19/31] packages/core-api: make App configLoader optional and synchronous when missing --- packages/core-api/src/app/App.tsx | 10 ++++++---- packages/test-utils/src/testUtils/appWrappers.tsx | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/core-api/src/app/App.tsx b/packages/core-api/src/app/App.tsx index 49d2291acd..4207a267af 100644 --- a/packages/core-api/src/app/App.tsx +++ b/packages/core-api/src/app/App.tsx @@ -43,7 +43,7 @@ type FullAppOptions = { plugins: BackstagePlugin[]; components: AppComponents; themes: AppTheme[]; - configLoader: AppConfigLoader; + configLoader?: AppConfigLoader; }; export class PrivateAppImpl implements BackstageApp { @@ -52,7 +52,7 @@ export class PrivateAppImpl implements BackstageApp { private readonly plugins: BackstagePlugin[]; private readonly components: AppComponents; private readonly themes: AppTheme[]; - private readonly configLoader: AppConfigLoader; + private readonly configLoader?: AppConfigLoader; constructor(options: FullAppOptions) { this.apis = options.apis; @@ -148,11 +148,13 @@ export class PrivateAppImpl implements BackstageApp { getProvider(): ComponentType<{}> { const Provider: FC<{}> = ({ children }) => { - const config = useAsync(this.configLoader); + // Keeping this synchronous when a config loader isn't set simplifies tests a lot + const hasConfig = Boolean(this.configLoader); + const config = useAsync(this.configLoader || (() => Promise.resolve({}))); let childNode = children; - if (config.loading) { + if (hasConfig && config.loading) { const { Progress } = this.components; childNode = ; } else if (config.error) { diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index 7849ed20cc..2450604976 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -66,7 +66,6 @@ export function wrapInTestApp( variant: 'light', }, ], - configLoader: async () => ({}), }); let Wrapper: ComponentType; From 9a6df0bf18dd17f8994ca0bf84d25f7081a910e7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 29 May 2020 10:20:22 +0200 Subject: [PATCH 20/31] packages/cli: call eslint directly --- packages/cli/config/eslint.backend.js | 2 +- packages/cli/config/eslint.js | 2 +- packages/cli/src/commands/lint.ts | 11 +++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/cli/config/eslint.backend.js b/packages/cli/config/eslint.backend.js index 619d3c72e0..4f45e232b2 100644 --- a/packages/cli/config/eslint.backend.js +++ b/packages/cli/config/eslint.backend.js @@ -32,7 +32,7 @@ module.exports = { ecmaVersion: 2018, sourceType: 'module', }, - ignorePatterns: ['**/dist/**', '**/build/**'], + ignorePatterns: ['.eslintrc.js', '**/dist/**'], rules: { 'no-console': 0, // Permitted in console programs 'new-cap': ['error', { capIsNew: false }], // Because Express constructs things e.g. like 'const r = express.Router()' diff --git a/packages/cli/config/eslint.js b/packages/cli/config/eslint.js index 0c6bfbe8e7..922867ea5a 100644 --- a/packages/cli/config/eslint.js +++ b/packages/cli/config/eslint.js @@ -39,7 +39,7 @@ module.exports = { version: 'detect', }, }, - ignorePatterns: ['**/dist/**', '**/build/**'], + ignorePatterns: ['.eslintrc.js', '**/dist/**'], rules: { 'import/no-duplicates': 'warn', 'import/no-extraneous-dependencies': [ diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts index 07819bacfb..7eeedcbe29 100644 --- a/packages/cli/src/commands/lint.ts +++ b/packages/cli/src/commands/lint.ts @@ -16,12 +16,19 @@ import { Command } from 'commander'; import { run } from '../lib/run'; +import { paths } from '../lib/paths'; export default async (cmd: Command) => { - const args = ['lint', '--max-warnings=0', '--format=codeframe']; + const args = [ + '--ext', + 'js,jsx,ts,tsx', + '--max-warnings=0', + '--format=codeframe', + paths.targetDir, + ]; if (cmd.fix) { args.push('--fix'); } - await run('web-scripts', args); + await run('eslint', args); }; From f67f928afc4a561784db45aa0e2f4c5b0fb0b9c1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 29 May 2020 10:52:00 +0200 Subject: [PATCH 21/31] packages/cli: remove direct web-scripts dependency and use config packages instead --- packages/cli/config/tsconfig.json | 2 +- packages/cli/package.json | 5 +- yarn.lock | 3007 +++-------------------------- 3 files changed, 260 insertions(+), 2754 deletions(-) diff --git a/packages/cli/config/tsconfig.json b/packages/cli/config/tsconfig.json index 652e990387..fb52420860 100644 --- a/packages/cli/config/tsconfig.json +++ b/packages/cli/config/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@spotify/web-scripts/config/tsconfig.json", + "extends": "@spotify/tsconfig", "exclude": ["**/*.test.*"], "compilerOptions": { "allowJs": true, diff --git a/packages/cli/package.json b/packages/cli/package.json index a15765c731..13c0fd4aa3 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -35,7 +35,8 @@ "@rollup/plugin-commonjs": "^11.0.2", "@rollup/plugin-json": "^4.0.2", "@rollup/plugin-node-resolve": "^7.1.1", - "@spotify/web-scripts": "^6.0.0", + "@spotify/eslint-config": "^7.0.1", + "@spotify/tsconfig": "^7.0.0", "@sucrase/webpack-loader": "^2.0.0", "bfj": "^7.0.2", "chalk": "^4.0.0", @@ -44,6 +45,7 @@ "css-loader": "^3.5.3", "dashify": "^2.0.0", "diff": "^4.0.2", + "eslint": "^7.1.0", "eslint-plugin-import": "^2.20.2", "eslint-plugin-monorepo": "^0.2.1", "fork-ts-checker-webpack-plugin": "^4.0.5", @@ -74,6 +76,7 @@ "tar": "^6.0.1", "ts-jest": "^26.0.0", "ts-loader": "^7.0.4", + "typescript": "^3.9.3", "url-loader": "^4.1.0", "webpack": "^4.41.6", "webpack-dev-server": "^3.10.3", diff --git a/yarn.lock b/yarn.lock index 80e3916f53..679f75cb36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -378,7 +378,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-bigint@^7.0.0", "@babel/plugin-syntax-bigint@^7.8.3": +"@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== @@ -441,7 +441,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== @@ -937,136 +937,6 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@commitlint/cli@^8.3.3": - version "8.3.5" - resolved "https://registry.npmjs.org/@commitlint/cli/-/cli-8.3.5.tgz#6d93a3a8b2437fa978999d3f6a336bcc70be3fd3" - integrity sha512-6+L0vbw55UEdht71pgWOE55SRgb+8OHcEwGDB234VlIBFGK9P2QOBU7MHiYJ5cjdjCQ0rReNrGjOHmJ99jwf0w== - dependencies: - "@commitlint/format" "^8.3.4" - "@commitlint/lint" "^8.3.5" - "@commitlint/load" "^8.3.5" - "@commitlint/read" "^8.3.4" - babel-polyfill "6.26.0" - chalk "2.4.2" - get-stdin "7.0.0" - lodash "4.17.15" - meow "5.0.0" - resolve-from "5.0.0" - resolve-global "1.0.0" - -"@commitlint/config-conventional@^8.3.3": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-8.3.4.tgz#fed13b3711690663b176c1f6b39c205a565618d2" - integrity sha512-w0Yc5+aVAjZgjYqx29igBOnVCj8O22gy3Vo6Fyp7PwoS7+AYS1x3sN7IBq6i7Ae15Mv5P+rEx1pkxXo5zOMe4g== - dependencies: - conventional-changelog-conventionalcommits "4.2.1" - -"@commitlint/ensure@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/ensure/-/ensure-8.3.4.tgz#6931677e4ca0fde71686ae3b7a367261647a341d" - integrity sha512-8NW77VxviLhD16O3EUd02lApMFnrHexq10YS4F4NftNoErKbKaJ0YYedktk2boKrtNRf/gQHY/Qf65edPx4ipw== - dependencies: - lodash "4.17.15" - -"@commitlint/execute-rule@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-8.3.4.tgz#1b63f0713b197889d90b76f9eea1abc010d256b1" - integrity sha512-f4HigYjeIBn9f7OuNv5zh2y5vWaAhNFrfeul8CRJDy82l3Y+09lxOTGxfF3uMXKrZq4LmuK6qvvRCZ8mUrVvzQ== - -"@commitlint/format@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/format/-/format-8.3.4.tgz#7cd1f0ba5a3289c8d14d7dac29ee1fc1597fe1d9" - integrity sha512-809wlQ/ND6CLZON+w2Rb3YM2TLNDfU2xyyqpZeqzf2reJNpySMSUAeaO/fNDJSOKIsOsR3bI01rGu6hv28k+Nw== - dependencies: - chalk "^2.0.1" - -"@commitlint/is-ignored@^8.3.5": - version "8.3.5" - resolved "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-8.3.5.tgz#e6f59496e1b1ce58020d519cd578ad0f43169199" - integrity sha512-Zo+8a6gJLFDTqyNRx53wQi/XTiz8mncvmWf/4oRG+6WRcBfjSSHY7KPVj5Y6UaLy2EgZ0WQ2Tt6RdTDeQiQplA== - dependencies: - semver "6.3.0" - -"@commitlint/lint@^8.3.5": - version "8.3.5" - resolved "https://registry.npmjs.org/@commitlint/lint/-/lint-8.3.5.tgz#627e75adb1cc803cc723e33cc2ba4aa27cbb9f0c" - integrity sha512-02AkI0a6PU6rzqUvuDkSi6rDQ2hUgkq9GpmdJqfai5bDbxx2939mK4ZO+7apbIh4H6Pae7EpYi7ffxuJgm+3hQ== - dependencies: - "@commitlint/is-ignored" "^8.3.5" - "@commitlint/parse" "^8.3.4" - "@commitlint/rules" "^8.3.4" - babel-runtime "^6.23.0" - lodash "4.17.15" - -"@commitlint/load@>6.1.1", "@commitlint/load@^8.3.5": - version "8.3.5" - resolved "https://registry.npmjs.org/@commitlint/load/-/load-8.3.5.tgz#3f059225ede92166ba94cf4c48e3d67c8b08b18a" - integrity sha512-poF7R1CtQvIXRmVIe63FjSQmN9KDqjRtU5A6hxqXBga87yB2VUJzic85TV6PcQc+wStk52cjrMI+g0zFx+Zxrw== - dependencies: - "@commitlint/execute-rule" "^8.3.4" - "@commitlint/resolve-extends" "^8.3.5" - babel-runtime "^6.23.0" - chalk "2.4.2" - cosmiconfig "^5.2.0" - lodash "4.17.15" - resolve-from "^5.0.0" - -"@commitlint/message@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/message/-/message-8.3.4.tgz#b4e50d14aa6e15a5ad0767b952a7953f3681d768" - integrity sha512-nEj5tknoOKXqBsaQtCtgPcsAaf5VCg3+fWhss4Vmtq40633xLq0irkdDdMEsYIx8rGR0XPBTukqzln9kAWCkcA== - -"@commitlint/parse@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/parse/-/parse-8.3.4.tgz#d741f8b9104b35d0f4c10938165b20cbf167f81e" - integrity sha512-b3uQvpUQWC20EBfKSfMRnyx5Wc4Cn778bVeVOFErF/cXQK725L1bYFvPnEjQO/GT8yGVzq2wtLaoEqjm1NJ/Bw== - dependencies: - conventional-changelog-angular "^1.3.3" - conventional-commits-parser "^3.0.0" - lodash "^4.17.11" - -"@commitlint/read@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/read/-/read-8.3.4.tgz#81a34283d8cd7b2acdf57829a91761e9c7791455" - integrity sha512-FKv1kHPrvcAG5j+OSbd41IWexsbLhfIXpxVC/YwQZO+FR0EHmygxQNYs66r+GnhD1EfYJYM4WQIqd5bJRx6OIw== - dependencies: - "@commitlint/top-level" "^8.3.4" - "@marionebl/sander" "^0.6.0" - babel-runtime "^6.23.0" - git-raw-commits "^2.0.0" - -"@commitlint/resolve-extends@^8.3.5": - version "8.3.5" - resolved "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-8.3.5.tgz#8fff800f292ac217ae30b1862f5f9a84b278310a" - integrity sha512-nHhFAK29qiXNe6oH6uG5wqBnCR+BQnxlBW/q5fjtxIaQALgfoNLHwLS9exzbIRFqwJckpR6yMCfgMbmbAOtklQ== - dependencies: - import-fresh "^3.0.0" - lodash "4.17.15" - resolve-from "^5.0.0" - resolve-global "^1.0.0" - -"@commitlint/rules@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/rules/-/rules-8.3.4.tgz#41da7e16c6b89af268fe81c87a158c1fd2ac82b1" - integrity sha512-xuC9dlqD5xgAoDFgnbs578cJySvwOSkMLQyZADb1xD5n7BNcUJfP8WjT9W1Aw8K3Wf8+Ym/ysr9FZHXInLeaRg== - dependencies: - "@commitlint/ensure" "^8.3.4" - "@commitlint/message" "^8.3.4" - "@commitlint/to-lines" "^8.3.4" - babel-runtime "^6.23.0" - -"@commitlint/to-lines@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-8.3.4.tgz#ce24963b6d86dbe51d88d5e3028ab28f38562e2e" - integrity sha512-5AvcdwRsMIVq0lrzXTwpbbG5fKRTWcHkhn/hCXJJ9pm1JidsnidS1y0RGkb3O50TEHGewhXwNoavxW9VToscUA== - -"@commitlint/top-level@^8.3.4": - version "8.3.4" - resolved "https://registry.npmjs.org/@commitlint/top-level/-/top-level-8.3.4.tgz#803fc6e8f5be5efa5f3551761acfca961f1d8685" - integrity sha512-nOaeLBbAqSZNpKgEtO6NAxmui1G8ZvLG+0wb4rvv6mWhPDzK1GNZkCd8FUZPahCoJ1iHDoatw7F8BbJLg4nDjg== - dependencies: - find-up "^4.0.0" - "@cypress/listr-verbose-renderer@0.4.1": version "0.4.1" resolved "https://registry.npmjs.org/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#a77492f4b11dcc7c446a34b3e28721afd33c642a" @@ -1412,15 +1282,6 @@ prop-types "^15.6.2" scheduler "^0.19.0" -"@iarna/cli@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@iarna/cli/-/cli-1.2.0.tgz#0f7af5e851afe895104583c4ca07377a8094d641" - integrity sha512-ukITQAqVs2n9HGmn3car/Ir7d3ta650iXhrG7pjr3EWdFmJuuOVWgYsu7ftsSe5VifEFFhjxVuX9+8F7L8hwcA== - dependencies: - signal-exit "^3.0.2" - update-notifier "^2.2.0" - yargs "^8.0.2" - "@istanbuljs/load-nyc-config@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" @@ -1436,16 +1297,6 @@ resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@jest/console@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/console/-/console-25.1.0.tgz#1fc765d44a1e11aec5029c08e798246bd37075ab" - integrity sha512-3P1DpqAMK/L07ag/Y9/Jup5iDEG9P4pRAuZiMQnU0JB3UOvCyYCjCoxr7sIA80SeyUCUKrr24fKAxVpmBgQonA== - dependencies: - "@jest/source-map" "^25.1.0" - chalk "^3.0.0" - jest-util "^25.1.0" - slash "^3.0.0" - "@jest/console@^26.0.1": version "26.0.1" resolved "https://registry.npmjs.org/@jest/console/-/console-26.0.1.tgz#62b3b2fa8990f3cbffbef695c42ae9ddbc8f4b39" @@ -1457,40 +1308,6 @@ jest-util "^26.0.1" slash "^3.0.0" -"@jest/core@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/core/-/core-25.1.0.tgz#3d4634fc3348bb2d7532915d67781cdac0869e47" - integrity sha512-iz05+NmwCmZRzMXvMo6KFipW7nzhbpEawrKrkkdJzgytavPse0biEnCNr2wRlyCsp3SmKaEY+SGv7YWYQnIdig== - dependencies: - "@jest/console" "^25.1.0" - "@jest/reporters" "^25.1.0" - "@jest/test-result" "^25.1.0" - "@jest/transform" "^25.1.0" - "@jest/types" "^25.1.0" - ansi-escapes "^4.2.1" - chalk "^3.0.0" - exit "^0.1.2" - graceful-fs "^4.2.3" - jest-changed-files "^25.1.0" - jest-config "^25.1.0" - jest-haste-map "^25.1.0" - jest-message-util "^25.1.0" - jest-regex-util "^25.1.0" - jest-resolve "^25.1.0" - jest-resolve-dependencies "^25.1.0" - jest-runner "^25.1.0" - jest-runtime "^25.1.0" - jest-snapshot "^25.1.0" - jest-util "^25.1.0" - jest-validate "^25.1.0" - jest-watcher "^25.1.0" - micromatch "^4.0.2" - p-each-series "^2.1.0" - realpath-native "^1.1.0" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - "@jest/core@^26.0.1": version "26.0.1" resolved "https://registry.npmjs.org/@jest/core/-/core-26.0.1.tgz#aa538d52497dfab56735efb00e506be83d841fae" @@ -1524,15 +1341,6 @@ slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/environment/-/environment-25.1.0.tgz#4a97f64770c9d075f5d2b662b5169207f0a3f787" - integrity sha512-cTpUtsjU4cum53VqBDlcW0E4KbQF03Cn0jckGPW/5rrE9tb+porD3+hhLtHAwhthsqfyF+bizyodTlsRA++sHg== - dependencies: - "@jest/fake-timers" "^25.1.0" - "@jest/types" "^25.1.0" - jest-mock "^25.1.0" - "@jest/environment@^26.0.1": version "26.0.1" resolved "https://registry.npmjs.org/@jest/environment/-/environment-26.0.1.tgz#82f519bba71959be9b483675ee89de8c8f72a5c8" @@ -1542,17 +1350,6 @@ "@jest/types" "^26.0.1" jest-mock "^26.0.1" -"@jest/fake-timers@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-25.1.0.tgz#a1e0eff51ffdbb13ee81f35b52e0c1c11a350ce8" - integrity sha512-Eu3dysBzSAO1lD7cylZd/CVKdZZ1/43SF35iYBNV1Lvvn2Undp3Grwsv8PrzvbLhqwRzDd4zxrY4gsiHc+wygQ== - dependencies: - "@jest/types" "^25.1.0" - jest-message-util "^25.1.0" - jest-mock "^25.1.0" - jest-util "^25.1.0" - lolex "^5.0.0" - "@jest/fake-timers@^26.0.1": version "26.0.1" resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.0.1.tgz#f7aeff13b9f387e9d0cac9a8de3bba538d19d796" @@ -1573,39 +1370,6 @@ "@jest/types" "^26.0.1" expect "^26.0.1" -"@jest/reporters@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-25.1.0.tgz#9178ecf136c48f125674ac328f82ddea46e482b0" - integrity sha512-ORLT7hq2acJQa8N+NKfs68ZtHFnJPxsGqmofxW7v7urVhzJvpKZG9M7FAcgh9Ee1ZbCteMrirHA3m5JfBtAaDg== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^25.1.0" - "@jest/environment" "^25.1.0" - "@jest/test-result" "^25.1.0" - "@jest/transform" "^25.1.0" - "@jest/types" "^25.1.0" - chalk "^3.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.0" - jest-haste-map "^25.1.0" - jest-resolve "^25.1.0" - jest-runtime "^25.1.0" - jest-util "^25.1.0" - jest-worker "^25.1.0" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^3.1.0" - terminal-link "^2.0.0" - v8-to-istanbul "^4.0.1" - optionalDependencies: - node-notifier "^6.0.0" - "@jest/reporters@^26.0.1": version "26.0.1" resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-26.0.1.tgz#14ae00e7a93e498cec35b0c00ab21c375d9b078f" @@ -1638,15 +1402,6 @@ optionalDependencies: node-notifier "^7.0.0" -"@jest/source-map@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-25.1.0.tgz#b012e6c469ccdbc379413f5c1b1ffb7ba7034fb0" - integrity sha512-ohf2iKT0xnLWcIUhL6U6QN+CwFWf9XnrM2a6ybL9NXxJjgYijjLSitkYHIdzkd8wFliH73qj/+epIpTiWjRtAA== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.3" - source-map "^0.6.0" - "@jest/source-map@^26.0.0": version "26.0.0" resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.0.0.tgz#fd7706484a7d3faf7792ae29783933bbf48a4749" @@ -1656,17 +1411,6 @@ graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/test-result@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-25.1.0.tgz#847af2972c1df9822a8200457e64be4ff62821f7" - integrity sha512-FZzSo36h++U93vNWZ0KgvlNuZ9pnDnztvaM7P/UcTx87aPDotG18bXifkf1Ji44B7k/eIatmMzkBapnAzjkJkg== - dependencies: - "@jest/console" "^25.1.0" - "@jest/transform" "^25.1.0" - "@jest/types" "^25.1.0" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - "@jest/test-result@^26.0.1": version "26.0.1" resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-26.0.1.tgz#1ffdc1ba4bc289919e54b9414b74c9c2f7b2b718" @@ -1677,16 +1421,6 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-25.1.0.tgz#4df47208542f0065f356fcdb80026e3c042851ab" - integrity sha512-WgZLRgVr2b4l/7ED1J1RJQBOharxS11EFhmwDqknpknE0Pm87HLZVS2Asuuw+HQdfQvm2aXL2FvvBLxOD1D0iw== - dependencies: - "@jest/test-result" "^25.1.0" - jest-haste-map "^25.1.0" - jest-runner "^25.1.0" - jest-runtime "^25.1.0" - "@jest/test-sequencer@^26.0.1": version "26.0.1" resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.0.1.tgz#b0563424728f3fe9e75d1442b9ae4c11da73f090" @@ -1698,28 +1432,6 @@ jest-runner "^26.0.1" jest-runtime "^26.0.1" -"@jest/transform@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/transform/-/transform-25.1.0.tgz#221f354f512b4628d88ce776d5b9e601028ea9da" - integrity sha512-4ktrQ2TPREVeM+KxB4zskAT84SnmG1vaz4S+51aTefyqn3zocZUnliLLm5Fsl85I3p/kFPN4CRp1RElIfXGegQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^25.1.0" - babel-plugin-istanbul "^6.0.0" - chalk "^3.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.3" - jest-haste-map "^25.1.0" - jest-regex-util "^25.1.0" - jest-util "^25.1.0" - micromatch "^4.0.2" - pirates "^4.0.1" - realpath-native "^1.1.0" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - "@jest/transform@^26.0.1": version "26.0.1" resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.0.1.tgz#0e3ecbb34a11cd4b2080ed0a9c4856cf0ceb0639" @@ -1750,16 +1462,6 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" -"@jest/types@^25.1.0": - version "25.1.0" - resolved "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz#b26831916f0d7c381e11dbb5e103a72aed1b4395" - integrity sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - "@jest/types@^25.5.0": version "25.5.0" resolved "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" @@ -2483,15 +2185,6 @@ npmlog "^4.1.2" write-file-atomic "^2.3.0" -"@marionebl/sander@^0.6.0": - version "0.6.1" - resolved "https://registry.npmjs.org/@marionebl/sander/-/sander-0.6.1.tgz#1958965874f24bc51be48875feb50d642fc41f7b" - integrity sha1-GViWWHTyS8Ub5Ih1/rUNZC/EH3s= - dependencies: - graceful-fs "^4.1.3" - mkdirp "^0.5.1" - rimraf "^2.5.2" - "@material-ui/core@^4.9.1": version "4.9.7" resolved "https://registry.npmjs.org/@material-ui/core/-/core-4.9.7.tgz#0c1caf123278770f34c5d8e9ecd9e1314f87a621" @@ -2638,18 +2331,6 @@ dependencies: "@octokit/types" "^2.0.0" -"@octokit/core@^2.4.0": - version "2.4.2" - resolved "https://registry.npmjs.org/@octokit/core/-/core-2.4.2.tgz#c22e583afc97e74015ea5bfd3ffb3ffc56c186ed" - integrity sha512-fUx/Qt774cgiPhb3HRKfdl6iufVL/ltECkwkCg373I4lIPYvAPY4cbidVZqyVqHI+ThAIlFlTW8FT4QHChv3Sg== - dependencies: - "@octokit/auth-token" "^2.4.0" - "@octokit/graphql" "^4.3.1" - "@octokit/request" "^5.3.1" - "@octokit/types" "^2.0.0" - before-after-hook "^2.1.0" - universal-user-agent "^5.0.0" - "@octokit/endpoint@^5.5.0": version "5.5.3" resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.3.tgz#0397d1baaca687a4c8454ba424a627699d97c978" @@ -2659,15 +2340,6 @@ is-plain-object "^3.0.0" universal-user-agent "^5.0.0" -"@octokit/graphql@^4.3.1": - version "4.3.1" - resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.3.1.tgz#9ee840e04ed2906c7d6763807632de84cdecf418" - integrity sha512-hCdTjfvrK+ilU2keAdqNBWOk+gm1kai1ZcdjRfB30oA3/T6n53UVJb7w0L5cR3/rhU91xT3HSqCd+qbvH06yxA== - dependencies: - "@octokit/request" "^5.3.0" - "@octokit/types" "^2.0.0" - universal-user-agent "^4.0.0" - "@octokit/plugin-enterprise-rest@^3.6.1": version "3.6.2" resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-3.6.2.tgz#74de25bef21e0182b4fa03a8678cd00a4e67e561" @@ -2680,13 +2352,6 @@ dependencies: "@octokit/types" "^2.0.1" -"@octokit/plugin-paginate-rest@^2.0.0": - version "2.0.2" - resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.0.2.tgz#fee7a81a4cc7d03784aaf9225499dd6e27f6d01e" - integrity sha512-HzODcSUt9mjErly26TlTOGZrhf9bmF/FEDQ2zln1izhgmIV6ulsjsHmgmR4VZ0wzVr/m52Eb6U2XuyS8fkcR1A== - dependencies: - "@octokit/types" "^2.0.1" - "@octokit/plugin-request-log@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e" @@ -2700,14 +2365,6 @@ "@octokit/types" "^2.0.1" deprecation "^2.3.1" -"@octokit/plugin-rest-endpoint-methods@^3.3.0": - version "3.3.1" - resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-3.3.1.tgz#279920ee391bd7e944ae4aa7fa435ba0c51fbb6a" - integrity sha512-iLAXPLWBZaP6ocy1GFfZUCzyN4cwg3y2JE6yZjQo0zLE3UaewC3TI68/TnS4ilyhXDxh81Jr1qwPN1AqTp8t3w== - dependencies: - "@octokit/types" "^2.0.1" - deprecation "^2.3.1" - "@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2": version "1.2.1" resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801" @@ -2717,7 +2374,7 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@^5.2.0", "@octokit/request@^5.3.0", "@octokit/request@^5.3.1": +"@octokit/request@^5.2.0": version "5.3.2" resolved "https://registry.npmjs.org/@octokit/request/-/request-5.3.2.tgz#1ca8b90a407772a1ee1ab758e7e0aced213b9883" integrity sha512-7NPJpg19wVQy1cs2xqXjjRq/RmtSomja/VSWnptfYwuBxLdbYh2UjhGi0Wx7B1v5Iw5GKhfFDQL7jM7SSp7K2g== @@ -2753,16 +2410,6 @@ once "^1.4.0" universal-user-agent "^4.0.0" -"@octokit/rest@^17.0.0": - version "17.1.1" - resolved "https://registry.npmjs.org/@octokit/rest/-/rest-17.1.1.tgz#357a9f6da687fc2ca9276715c1541562bd2c1581" - integrity sha512-Cn9XpevTJdQj/GbACY1WjArDabPpdAhvlS5zoCdZ/chiKbl4vutL1X1VeJHzDLK0K6BdZXXe4SnEPN31wKPA7A== - dependencies: - "@octokit/core" "^2.4.0" - "@octokit/plugin-paginate-rest" "^2.0.0" - "@octokit/plugin-request-log" "^1.0.0" - "@octokit/plugin-rest-endpoint-methods" "^3.3.0" - "@octokit/types@^2.0.0", "@octokit/types@^2.0.1": version "2.5.0" resolved "https://registry.npmjs.org/@octokit/types/-/types-2.5.0.tgz#f1bbd147e662ae2c79717d518aac686e58257773" @@ -2825,81 +2472,6 @@ dependencies: any-observable "^0.3.0" -"@semantic-release/commit-analyzer@^8.0.0": - version "8.0.1" - resolved "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz#5d2a37cd5a3312da0e3ac05b1ca348bf60b90bca" - integrity sha512-5bJma/oB7B4MtwUkZC2Bf7O1MHfi4gWe4mA+MIQ3lsEV0b422Bvl1z5HRpplDnMLHH3EXMoRdEng6Ds5wUqA3A== - dependencies: - conventional-changelog-angular "^5.0.0" - conventional-commits-filter "^2.0.0" - conventional-commits-parser "^3.0.7" - debug "^4.0.0" - import-from "^3.0.0" - lodash "^4.17.4" - micromatch "^4.0.2" - -"@semantic-release/error@^2.2.0": - version "2.2.0" - resolved "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz#ee9d5a09c9969eade1ec864776aeda5c5cddbbf0" - integrity sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg== - -"@semantic-release/github@^7.0.0": - version "7.0.5" - resolved "https://registry.npmjs.org/@semantic-release/github/-/github-7.0.5.tgz#042b515cbae8695aa60bc4ed17722c34512a5b89" - integrity sha512-1nJCMeomspRIXKiFO3VXtkUMbIBEreYLFNBdWoLjvlUNcEK0/pEbupEZJA3XHfJuSzv43u3OLpPhF/JBrMuv+A== - dependencies: - "@octokit/rest" "^17.0.0" - "@semantic-release/error" "^2.2.0" - aggregate-error "^3.0.0" - bottleneck "^2.18.1" - debug "^4.0.0" - dir-glob "^3.0.0" - fs-extra "^9.0.0" - globby "^11.0.0" - http-proxy-agent "^4.0.0" - https-proxy-agent "^5.0.0" - issue-parser "^6.0.0" - lodash "^4.17.4" - mime "^2.4.3" - p-filter "^2.0.0" - p-retry "^4.0.0" - url-join "^4.0.0" - -"@semantic-release/npm@^7.0.0": - version "7.0.5" - resolved "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.0.5.tgz#61c45691abb863f6939cca6aac958d3c22508632" - integrity sha512-D+oEmsx9aHE1q806NFQwSC9KdBO8ri/VO99eEz0wWbX2jyLqVyWr7t0IjKC8aSnkkQswg/4KN/ZjfF6iz1XOpw== - dependencies: - "@semantic-release/error" "^2.2.0" - aggregate-error "^3.0.0" - execa "^4.0.0" - fs-extra "^9.0.0" - lodash "^4.17.15" - nerf-dart "^1.0.0" - normalize-url "^5.0.0" - npm "^6.10.3" - rc "^1.2.8" - read-pkg "^5.0.0" - registry-auth-token "^4.0.0" - semver "^7.1.2" - tempy "^0.5.0" - -"@semantic-release/release-notes-generator@^9.0.0": - version "9.0.1" - resolved "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.1.tgz#732d285d103064f2a64f08a32031551ebb4f918b" - integrity sha512-bOoTiH6SiiR0x2uywSNR7uZcRDl22IpZhj+Q5Bn0v+98MFtOMhCxFhbrKQjhbYoZw7vps1mvMRmFkp/g6R9cvQ== - dependencies: - conventional-changelog-angular "^5.0.0" - conventional-changelog-writer "^4.0.0" - conventional-commits-filter "^2.0.0" - conventional-commits-parser "^3.0.0" - debug "^4.0.0" - get-stream "^5.0.0" - import-from "^3.0.0" - into-stream "^5.0.0" - lodash "^4.17.4" - read-pkg-up "^7.0.0" - "@sheerun/mutationobserver-shim@^0.3.2": version "0.3.3" resolved "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" @@ -2924,10 +2496,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@spotify/eslint-config-base@^6.1.0": - version "6.1.0" - resolved "https://registry.npmjs.org/@spotify/eslint-config-base/-/eslint-config-base-6.1.0.tgz#b48d2764049d56a7d83a95709ec1e6733cb19f2a" - integrity sha512-oxR3OBBrms09Ih6yPrqcaeKgwchdw9XgRvKsF6x6uPiMy0OVYald/+GkBtyQy+IChD14WStV/XosqNxEZeTJ4Q== +"@spotify/eslint-config-base@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@spotify/eslint-config-base/-/eslint-config-base-7.0.0.tgz#36804ae09ec938f1aa5f9464ea993f3f151cfaa8" + integrity sha512-XRTrTRyRRYBxPYINKNHw4B8QWlA3p4I+id/Po2sMdejtXH3LZgDgIjdschUZSdQ6J6dVYDdaVykdizRM9I+G6Q== "@spotify/eslint-config-oss@^1.0.1": version "1.0.2" @@ -2936,86 +2508,51 @@ dependencies: eslint-plugin-notice "^0.9.10" -"@spotify/eslint-config-react@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@spotify/eslint-config-react/-/eslint-config-react-6.0.0.tgz#9cfc88362c7ffcd14e4dde73c196d1bc8583051d" - integrity sha512-Tb88Yvu9lAjT/isKbebmOoxBAmjreDFH4lQfXxoFcW56Wl78l2yvLo0LkPV8lOx5+lKfX0BbFiBBpwl+jCaflg== +"@spotify/eslint-config-react@^7.0.1": + version "7.0.1" + resolved "https://registry.npmjs.org/@spotify/eslint-config-react/-/eslint-config-react-7.0.1.tgz#2e70de9d7911ea9aeaa55a83a332220a28f6c431" + integrity sha512-HNDHvm19EaBXiDgsg52mjMgKWZTeA0hO2Q75ACNwb8UtjIKkANqyyuzyDGo8jiGMbWIm6wJjShlRtT95emNlqQ== -"@spotify/eslint-config-typescript@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@spotify/eslint-config-typescript/-/eslint-config-typescript-6.0.0.tgz#8ae8469d2a0e219d71abaf2da14f8659c3912a34" - integrity sha512-cK1iHhfMgvZFPANqLoChhgUQ1oqH+qTWILGvcsc6HylzVt9/kM0SyjGcDuZKj+CP6TecJODdyHgb5U6U+O5gKw== +"@spotify/eslint-config-typescript@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@spotify/eslint-config-typescript/-/eslint-config-typescript-7.0.0.tgz#fc5227e3344f74b41ac3a530df24a95ac13254e4" + integrity sha512-28I/SAf68NKbWZ5IY0WYMa0D18PxWdC9DP9gRbOTlZufmsS8jEgqf3zBUWmP6XOf1nihpKWcqvbFUG5H7/JYXA== -"@spotify/eslint-config@^6.1.0": - version "6.1.0" - resolved "https://registry.npmjs.org/@spotify/eslint-config/-/eslint-config-6.1.0.tgz#67ef537c4419ecf275f790a79ce988820b3f5a95" - integrity sha512-pRfRFkW9XMHrzSErzzUxMRs/e+IL0i0o8crgMJJgk0J56+f0rQaXWkeDrI9HCw1uCkXLEwUoNPe+Rdd6cDk/lA== +"@spotify/eslint-config@^7.0.1": + version "7.0.1" + resolved "https://registry.npmjs.org/@spotify/eslint-config/-/eslint-config-7.0.1.tgz#07a21cfd7fce89cfc2c6dd5ea5d747e741201b66" + integrity sha512-8GI/TZGUhS4pr7oipT2MjrZFRgXcKzk9YImEusUdD2f5vlCniRFIBQNrvTMkyjfdQqvIVqJPLcdVPXeAgprsMw== dependencies: - "@spotify/eslint-config-base" "^6.1.0" - "@spotify/eslint-config-react" "^6.0.0" - "@spotify/eslint-config-typescript" "^6.0.0" - "@spotify/web-scripts-utils" "^6.0.0" + "@spotify/eslint-config-base" "^7.0.0" + "@spotify/eslint-config-react" "^7.0.1" + "@spotify/eslint-config-typescript" "^7.0.0" + "@spotify/web-scripts-utils" "^7.0.0" "@typescript-eslint/eslint-plugin" "^2.14.0" "@typescript-eslint/parser" "^2.14.0" eslint-config-prettier "^6.0.0" eslint-plugin-jest "^23.6.0" eslint-plugin-jsx-a11y "^6.2.1" eslint-plugin-react "^7.12.4" - -"@spotify/prettier-config@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-6.0.0.tgz#f3a72cf290af8f5b57e89fc65e6eaff8178a6e83" - integrity sha512-lO/ykZ/GNtzH63mFzs1VeqOVNCZwQJyZm/PBNBZuYk3hnWOfDC8XA5G/D4opV/gxqkED5+Ek7LSAnPcQNv/wUA== + eslint-plugin-react-hooks "^4.0.0" "@spotify/prettier-config@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-7.0.0.tgz#47750979d1282197295108b6958360660a955c16" integrity sha512-lIMcx/2oDqTtW84iHKkRJe+8U6HK6GPwWH5sJp9UEHcDpdXomOQYvwcGXy2I2zwPQQ14gYYE6nEJuSnnYqsYRw== -"@spotify/tsconfig@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@spotify/tsconfig/-/tsconfig-6.0.0.tgz#bf9fd0b8188494d87ba6c172f0030376d2aa5dd8" - integrity sha512-B+T6fcDRJg3x1G8wrqUQ+xgu6JYWBwPHeVxKybRGHLt4ciDmzJUvtWthXt8Fg3DqvaKnLnfXLcGOp8TiG+f0kA== +"@spotify/tsconfig@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@spotify/tsconfig/-/tsconfig-7.0.0.tgz#41c402f4eb6d3147bc18427a35205151cbb32cd5" + integrity sha512-MeRFUPMXWBSm6yaUWiESaQsF9B+9Rn1F/w5hbHHzcunc45teXBcgsOrJu1uDOEkhP/9lP0fefuodpP+TYWM1LQ== -"@spotify/web-scripts-utils@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@spotify/web-scripts-utils/-/web-scripts-utils-6.0.0.tgz#64642e79a894058510b0b4a239b117323080e853" - integrity sha512-o3htse1lyhLCabmYoQcI2qCsYV0PW6dpnYHhKAF/iycIglzz4/tXOk3EA/MQVlo6bo7crdr++3OeU4Dyk2CsWw== +"@spotify/web-scripts-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@spotify/web-scripts-utils/-/web-scripts-utils-7.0.0.tgz#8c6b8039fc645a36ac48629eb9ba06600f4d828a" + integrity sha512-McMy0j60lxOHjgDjegthZqEWN/PabphiM30A/mI/Y7xh9+JFnYWBTSm/wgn6EW2BsPpV631xSYYkk6B1Ph14Fw== dependencies: glob "^7.1.4" read-pkg-up "^7.0.1" -"@spotify/web-scripts@^6.0.0": - version "6.1.0" - resolved "https://registry.npmjs.org/@spotify/web-scripts/-/web-scripts-6.1.0.tgz#3fb52aa9c77c4724e056a33e5b5994b327594278" - integrity sha512-1QVbd7HtIlYLIuNwR7Er/S9p3HLmXOFZAwmRLQ0xe67G1/gqIQOXpuMuembWLyTqi15efMrpNBlmvH64eW7nsw== - dependencies: - "@commitlint/cli" "^8.3.3" - "@commitlint/config-conventional" "^8.3.3" - "@spotify/eslint-config" "^6.1.0" - "@spotify/prettier-config" "^6.0.0" - "@spotify/tsconfig" "^6.0.0" - "@spotify/web-scripts-utils" "^6.0.0" - "@types/cross-spawn" "^6.0.0" - "@types/debug" "^4.1.2" - "@types/jest" "^25.1.0" - "@types/react" "^16.8.19" - "@types/react-dom" "^16.8.4" - commander "^4.0.1" - commitizen "^4.0.3" - cross-spawn-promise "^0.10.1" - cz-conventional-changelog "^3.0.2" - debug "^4.1.1" - eslint "^6.8.0" - jest "^25.1.0" - jest-config "^25.1.0" - jest-junit "^10.0.0" - lint-staged "^10.0.4" - prettier "^1.18.2" - semantic-release "^17.0.1" - ts-jest "^25.2.1" - typescript "^3.7.4" - "@storybook/addon-actions@^5.3.17": version "5.3.18" resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-5.3.18.tgz#e3e3b1475cebc9bdd2d563822fba9ac662b2601a" @@ -3832,27 +3369,11 @@ "@theme-ui/core" "^0.3.1" "@theme-ui/mdx" "^0.3.0" -"@tootallnate/once@1": - version "1.0.0" - resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz#9c13c2574c92d4503b005feca8f2e16cc1611506" - integrity sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA== - "@types/anymatch@*": version "1.3.1" resolved "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== -"@types/babel__core@^7.1.0": - version "7.1.6" - resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.6.tgz#16ff42a5ae203c9af1c6e190ed1f30f83207b610" - integrity sha512-tTnhWszAqvXnhW7m5jQU9PomXSiKXk2sFxpahXvI20SZKu9ylPi8WtIxueZ6ehDWikPT0jeFujMj3X4ZHuf3Tg== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - "@types/babel__core@^7.1.7": version "7.1.7" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89" @@ -3973,13 +3494,6 @@ dependencies: "@types/express" "*" -"@types/cross-spawn@^6.0.0": - version "6.0.1" - resolved "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.1.tgz#60fa0c87046347c17d9735e5289e72b804ca9b63" - integrity sha512-MtN1pDYdI6D6QFDzy39Q+6c9rl2o/xN7aWGe6oZuzqq5N6+YuwFsWiEAv3dNzvzN9YzU+itpN8lBzFpphQKLAw== - dependencies: - "@types/node" "*" - "@types/cssnano@*": version "4.0.0" resolved "https://registry.npmjs.org/@types/cssnano/-/cssnano-4.0.0.tgz#f1bb29d6d0813861a3d87e02946b2988d0110d4e" @@ -3992,11 +3506,6 @@ resolved "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.2.1.tgz#c28803ea36fe29788db69efa0ad6c2dc09544e83" integrity sha512-jqK+I36uz4kTBjyk39meed5y31Ab+tXYN/x1dn3nZEus9yOHCLc+VrcIYLc/aSQ0Y7tMPRlIhLetulME76EiiA== -"@types/debug@^4.1.2": - version "4.1.5" - resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" - integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== - "@types/diff@^4.0.2": version "4.0.2" resolved "https://registry.npmjs.org/@types/diff/-/diff-4.0.2.tgz#2e9bb89f9acc3ab0108f0f3dc4dbdcf2fff8a99c" @@ -4165,7 +3674,7 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" -"@types/jest@*", "@types/jest@^25.1.0": +"@types/jest@*": version "25.2.1" resolved "https://registry.npmjs.org/@types/jest/-/jest-25.2.1.tgz#9544cd438607955381c1bdbdb97767a249297db5" integrity sha512-msra1bCaAeEdkSyA0CZ6gW1ukMIvZ5YoJkdXw/qhQdsuuDlFTcEUrUw8CLCPt2rVRUfXlClVvK2gvPs9IokZaA== @@ -4350,7 +3859,7 @@ "@types/webpack" "*" "@types/webpack-dev-server" "*" -"@types/react-dom@*", "@types/react-dom@^16.8.4": +"@types/react-dom@*": version "16.9.5" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.5.tgz#5de610b04a35d07ffd8f44edad93a71032d9aaa7" integrity sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg== @@ -4417,7 +3926,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.8.19", "@types/react@^16.9": +"@types/react@*", "@types/react@^16.9": version "16.9.25" resolved "https://registry.npmjs.org/@types/react/-/react-16.9.25.tgz#6ae2159b40138c792058a23c3c04fd3db49e929e" integrity sha512-Dlj2V72cfYLPNscIG3/SMUOzhzj7GK3bpSrfefwt2YT9GLynvLCCZjbhyF6VsT0q0+aRACRX03TDJGb7cA0cqg== @@ -4444,11 +3953,6 @@ dependencies: "@types/node" "*" -"@types/retry@^0.12.0": - version "0.12.0" - resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" - integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== - "@types/rollup-plugin-peer-deps-external@^2.2.0": version "2.2.0" resolved "https://registry.npmjs.org/@types/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.0.tgz#eae7d8b9d27fa037f5bcaded24e389f85b81973c" @@ -4897,7 +4401,7 @@ mkdirp-promise "^5.0.1" mz "^2.5.0" -JSONStream@^1.0.4, JSONStream@^1.3.4, JSONStream@^1.3.5: +JSONStream@^1.0.4, JSONStream@^1.3.4: version "1.3.5" resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== @@ -4910,7 +4414,7 @@ abab@^2.0.0, abab@^2.0.3: resolved "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== -abbrev@1, abbrev@~1.1.1: +abbrev@1: version "1.1.1" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== @@ -4923,7 +4427,7 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-globals@^4.1.0, acorn-globals@^4.3.2: +acorn-globals@^4.1.0: version "4.3.4" resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== @@ -4964,7 +4468,7 @@ acorn@^6.0.1, acorn@^6.4.1: resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.1.0, acorn@^7.1.1: +acorn@^7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== @@ -4981,13 +4485,6 @@ agent-base@4, agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" -agent-base@6: - version "6.0.0" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a" - integrity sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw== - dependencies: - debug "4" - agent-base@~4.2.1: version "4.2.1" resolved "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" @@ -5058,13 +4555,6 @@ alphanum-sort@^1.0.0: resolved "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= -ansi-align@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" - integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38= - dependencies: - string-width "^2.0.0" - ansi-align@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" @@ -5082,7 +4572,7 @@ ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: +ansi-escapes@^4.2.1: version "4.3.1" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== @@ -5141,16 +4631,6 @@ ansi-to-html@^0.6.11: dependencies: entities "^1.1.2" -ansicolors@~0.3.2: - version "0.3.2" - resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" - integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= - -ansistyles@~0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" - integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk= - any-observable@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" @@ -5221,12 +4701,12 @@ app-root-dir@^1.0.2: resolved "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz#38187ec2dea7577fff033ffcb12172692ff6e118" integrity sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg= -aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -"aproba@^1.1.2 || 2", aproba@^2.0.0: +aproba@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== @@ -5236,11 +4716,6 @@ arch@2.1.1: resolved "https://registry.npmjs.org/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e" integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg== -archy@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" @@ -5261,11 +4736,6 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -argv-formatter@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz#a0ca0cbc29a5b73e836eebe1cbf6c5e0e4eb82f9" - integrity sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk= - aria-query@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" @@ -5580,19 +5050,6 @@ babel-helper-to-multiple-sequence-expressions@^0.5.0: resolved "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d" integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA== -babel-jest@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-25.1.0.tgz#206093ac380a4b78c4404a05b3277391278f80fb" - integrity sha512-tz0VxUhhOE2y+g8R2oFrO/2VtVjA1lkJeavlhExuRBg3LdNJY9gwQ+Vcvqt9+cqy71MCTJhewvTB7Qtnnr9SWg== - dependencies: - "@jest/transform" "^25.1.0" - "@jest/types" "^25.1.0" - "@types/babel__core" "^7.1.0" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^25.1.0" - chalk "^3.0.0" - slash "^3.0.0" - babel-jest@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-26.0.1.tgz#450139ce4b6c17174b136425bda91885c397bc46" @@ -5646,13 +5103,6 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.1.0.tgz#fb62d7b3b53eb36c97d1bc7fec2072f9bd115981" - integrity sha512-oIsopO41vW4YFZ9yNYoLQATnnN46lp+MZ6H4VvPKFkcc2/fkl3CfE/NZZSmnEIEsJRmJAgkVEK0R7Zbl50CpTw== - dependencies: - "@types/babel__traverse" "^7.0.6" - babel-plugin-jest-hoist@^26.0.0: version "26.0.0" resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.0.0.tgz#fd1d35f95cf8849fc65cb01b5e58aedd710b34a8" @@ -5825,15 +5275,6 @@ babel-plugin-transform-undefined-to-void@^6.9.4: resolved "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280" integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA= -babel-polyfill@6.26.0: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" - integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= - dependencies: - babel-runtime "^6.26.0" - core-js "^2.5.0" - regenerator-runtime "^0.10.5" - babel-preset-current-node-syntax@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6" @@ -5850,15 +5291,6 @@ babel-preset-current-node-syntax@^0.1.2: "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -babel-preset-jest@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.1.0.tgz#d0aebfebb2177a21cde710996fce8486d34f1d33" - integrity sha512-eCGn64olaqwUMaugXsTtGAM2I0QTahjEtnRu0ql8Ie+gDWAc1N6wqN0k2NilnyTunM69Pad7gJY7LOtwLimoFQ== - dependencies: - "@babel/plugin-syntax-bigint" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - babel-plugin-jest-hoist "^25.1.0" - babel-preset-jest@^26.0.0: version "26.0.0" resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.0.0.tgz#1eac82f513ad36c4db2e9263d7c485c825b1faa6" @@ -5896,7 +5328,7 @@ babel-preset-jest@^26.0.0: babel-plugin-transform-undefined-to-void "^6.9.4" lodash "^4.17.11" -babel-runtime@6.26.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0: +babel-runtime@6.26.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -5961,7 +5393,7 @@ bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2: dependencies: tweetnacl "^0.14.3" -before-after-hook@^2.0.0, before-after-hook@^2.1.0: +before-after-hook@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== @@ -5981,18 +5413,6 @@ big.js@^5.2.2: resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== -bin-links@^1.1.2, bin-links@^1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/bin-links/-/bin-links-1.1.7.tgz#34b79ea9d0e575d7308afeff0c6b2fc24c793359" - integrity sha512-/eaLaTu7G7/o7PV04QPy1HRT65zf+1tFkPGv0sPTV0tRwufooYBQO3zrcyGgm+ja+ZtBf2GEuKjDRJ2pPG+yqA== - dependencies: - bluebird "^3.5.3" - cmd-shim "^3.0.0" - gentle-fs "^2.3.0" - graceful-fs "^4.1.15" - npm-normalize-package-bin "^1.0.0" - write-file-atomic "^2.3.0" - binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -6062,11 +5482,6 @@ boolbase@^1.0.0, boolbase@~1.0.0: resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= -bottleneck@^2.18.1: - version "2.19.5" - resolved "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" - integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== - bowser@2.9.0: version "2.9.0" resolved "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz#3bed854233b419b9a7422d9ee3e85504373821c9" @@ -6077,19 +5492,6 @@ bowser@^1.7.3: resolved "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a" integrity sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ== -boxen@^1.2.1: - version "1.3.0" - resolved "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" - integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw== - dependencies: - ansi-align "^2.0.0" - camelcase "^4.0.0" - chalk "^2.0.1" - cli-boxes "^1.0.0" - string-width "^2.0.0" - term-size "^1.2.0" - widest-line "^2.0.0" - boxen@^4.1.0, boxen@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" @@ -6145,13 +5547,6 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browser-resolve@^1.11.3: - version "1.11.3" - resolved "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -6394,21 +5789,11 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cachedir@2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/cachedir/-/cachedir-2.2.0.tgz#19afa4305e05d79e417566882e0c8f960f62ff0e" - integrity sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ== - cachedir@2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== -call-limit@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/call-limit/-/call-limit-1.1.1.tgz#ef15f2670db3f1992557e2d965abc459e6e358d4" - integrity sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ== - call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" @@ -6468,7 +5853,7 @@ camelcase@^2.0.0: resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= -camelcase@^4.0.0, camelcase@^4.1.0: +camelcase@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= @@ -6515,19 +5900,6 @@ capture-exit@^2.0.0: dependencies: rsvp "^4.8.4" -capture-stack-trace@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" - integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw== - -cardinal@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" - integrity sha1-fMEFXYItISlU0HsIXeolHMe8VQU= - dependencies: - ansicolors "~0.3.2" - redeyed "~2.1.0" - case-sensitive-paths-webpack-plugin@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7" @@ -6538,7 +5910,7 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -6643,7 +6015,7 @@ chokidar@^3.2.2, chokidar@^3.3.0, chokidar@^3.3.1: optionalDependencies: fsevents "~2.1.2" -chownr@^1.1.1, chownr@^1.1.2, chownr@^1.1.4: +chownr@^1.1.1, chownr@^1.1.2: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -6660,23 +6032,11 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -ci-info@^1.5.0: - version "1.6.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -cidr-regex@^2.0.10: - version "2.0.10" - resolved "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz#af13878bd4ad704de77d6dc800799358b3afa70d" - integrity sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q== - dependencies: - ip-regex "^2.1.0" - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -6719,24 +6079,11 @@ clean-stack@^2.0.0: resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-boxes@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" - integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= - cli-boxes@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d" integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w== -cli-columns@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz#6732d972979efc2ae444a1f08e08fa139c96a18e" - integrity sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4= - dependencies: - string-width "^2.0.0" - strip-ansi "^3.0.1" - cli-cursor@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" @@ -6763,7 +6110,7 @@ cli-spinners@^2.2.0: resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz#e8b988d9206c692302d8ee834e7a85c0144d8f77" integrity sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ== -cli-table3@0.5.1, cli-table3@^0.5.0, cli-table3@^0.5.1: +cli-table3@0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== @@ -6773,13 +6120,6 @@ cli-table3@0.5.1, cli-table3@^0.5.0, cli-table3@^0.5.1: optionalDependencies: colors "^1.1.2" -cli-table@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" - integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= - dependencies: - colors "1.0.3" - cli-truncate@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" @@ -6802,24 +6142,6 @@ clipboard@^2.0.0: select "^1.1.2" tiny-emitter "^2.0.0" -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - cliui@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -6875,14 +6197,6 @@ clsx@^1.0.1, clsx@^1.0.2, clsx@^1.0.4, clsx@^1.1.0: resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== -cmd-shim@^3.0.0, cmd-shim@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-3.0.3.tgz#2c35238d3df37d98ecdd7d5f6b8dc6b21cadc7cb" - integrity sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA== - dependencies: - graceful-fs "^4.1.2" - mkdirp "~0.5.0" - co@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -6991,11 +6305,6 @@ colornames@^1.1.1: resolved "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= -colors@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - colors@^1.1.2, colors@^1.2.1: version "1.4.0" resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" @@ -7009,7 +6318,7 @@ colorspace@1.1.x: color "3.0.x" text-hex "1.0.x" -columnify@^1.5.4, columnify@~1.5.4: +columnify@^1.5.4: version "1.5.4" resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= @@ -7049,27 +6358,6 @@ commander@^5.1.0: resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commitizen@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.0.3.tgz#c19a4213257d0525b85139e2f36db7cc3b4f6dae" - integrity sha512-lxu0F/Iq4dudoFeIl5pY3h3CQJzkmQuh3ygnaOvqhAD8Wu2pYBI17ofqSuPHNsBTEOh1r1AVa9kR4Hp0FAHKcQ== - dependencies: - cachedir "2.2.0" - cz-conventional-changelog "3.0.1" - dedent "0.7.0" - detect-indent "6.0.0" - find-node-modules "2.0.0" - find-root "1.1.0" - fs-extra "8.1.0" - glob "7.1.4" - inquirer "6.5.0" - is-utf8 "^0.2.1" - lodash "4.17.15" - minimist "1.2.0" - shelljs "0.7.6" - strip-bom "4.0.0" - strip-json-comments "3.0.1" - common-tags@1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" @@ -7150,7 +6438,7 @@ concat-with-sourcemaps@^1.1.0: dependencies: source-map "^0.6.1" -config-chain@^1.1.11, config-chain@^1.1.12: +config-chain@^1.1.11: version "1.1.12" resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== @@ -7158,18 +6446,6 @@ config-chain@^1.1.11, config-chain@^1.1.12: ini "^1.3.4" proto-list "~1.2.1" -configstore@^3.0.0: - version "3.1.2" - resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" - integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw== - dependencies: - dot-prop "^4.1.0" - graceful-fs "^4.1.2" - make-dir "^1.0.0" - unique-string "^1.0.0" - write-file-atomic "^2.0.0" - xdg-basedir "^3.0.0" - configstore@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" @@ -7192,7 +6468,7 @@ console-browserify@^1.1.0: resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: +console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= @@ -7224,15 +6500,7 @@ content-type@~1.0.4: resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -conventional-changelog-angular@^1.3.3: - version "1.6.6" - resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-1.6.6.tgz#b27f2b315c16d0a1f23eb181309d0e6a4698ea0f" - integrity sha512-suQnFSqCxRwyBxY68pYTsFkG0taIdinHLNEAX5ivtw8bCRnIgnpvcHmlR/yjUyZIrNPYAoXlY1WiEKWgSE4BNg== - dependencies: - compare-func "^1.3.1" - q "^1.5.1" - -conventional-changelog-angular@^5.0.0, conventional-changelog-angular@^5.0.3: +conventional-changelog-angular@^5.0.3: version "5.0.6" resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz#269540c624553aded809c29a3508fdc2b544c059" integrity sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA== @@ -7240,15 +6508,6 @@ conventional-changelog-angular@^5.0.0, conventional-changelog-angular@^5.0.3: compare-func "^1.3.1" q "^1.5.1" -conventional-changelog-conventionalcommits@4.2.1: - version "4.2.1" - resolved "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.1.tgz#d6cb2e2c5d7bfca044a08b9dba84b4082e1a1bd9" - integrity sha512-vC02KucnkNNap+foDKFm7BVUSDAXktXrUJqGszUuYnt6T0J2azsbYz/w9TDc3VsrW2v6JOtiQWVcgZnporHr4Q== - dependencies: - compare-func "^1.3.1" - lodash "^4.2.1" - q "^1.5.1" - conventional-changelog-core@^3.1.6: version "3.2.3" resolved "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-3.2.3.tgz#b31410856f431c847086a7dcb4d2ca184a7d88fb" @@ -7273,7 +6532,7 @@ conventional-changelog-preset-loader@^2.1.1: resolved "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.0.tgz#580fa8ab02cef22c24294d25e52d7ccd247a9a6a" integrity sha512-/rHb32J2EJnEXeK4NpDgMaAVTFZS3o1ExmjKMtYVgIC4MQn0vkNSbYpdGRotkfGGRWiqk3Ri3FBkiZGbAfIfOQ== -conventional-changelog-writer@^4.0.0, conventional-changelog-writer@^4.0.6: +conventional-changelog-writer@^4.0.6: version "4.0.11" resolved "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz#9f56d2122d20c96eb48baae0bf1deffaed1edba4" integrity sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw== @@ -7289,17 +6548,7 @@ conventional-changelog-writer@^4.0.0, conventional-changelog-writer@^4.0.6: split "^1.0.0" through2 "^3.0.0" -conventional-commit-types@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.3.0.tgz#bc3c8ebba0a9e4b3ecc548f1d0674e251ab8be22" - integrity sha512-6iB39PrcGYdz0n3z31kj6/Km6mK9hm9oMRhwcLnKxE7WNoeRKZbTAobliKrbYZ5jqyCvtcVEfjCiaEzhL3AVmQ== - -conventional-commit-types@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz#7c9214e58eae93e85dd66dbfbafe7e4fffa2365b" - integrity sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg== - -conventional-commits-filter@^2.0.0, conventional-commits-filter@^2.0.2: +conventional-commits-filter@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz#f122f89fbcd5bb81e2af2fcac0254d062d1039c1" integrity sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ== @@ -7307,7 +6556,7 @@ conventional-commits-filter@^2.0.0, conventional-commits-filter@^2.0.2: lodash.ismatch "^4.4.0" modify-values "^1.0.0" -conventional-commits-parser@^3.0.0, conventional-commits-parser@^3.0.3, conventional-commits-parser@^3.0.7: +conventional-commits-parser@^3.0.3: version "3.0.8" resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz#23310a9bda6c93c874224375e72b09fb275fe710" integrity sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ== @@ -7401,7 +6650,7 @@ core-js-pure@^3.0.0, core-js-pure@^3.0.1: resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== -core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5: +core-js@^2.4.0, core-js@^2.6.5: version "2.6.11" resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== @@ -7443,7 +6692,7 @@ cosmiconfig@6.0.0, cosmiconfig@^6.0.0: path-type "^4.0.0" yaml "^1.7.2" -cosmiconfig@^5.0.0, cosmiconfig@^5.1.0, cosmiconfig@^5.2.0, cosmiconfig@^5.2.1: +cosmiconfig@^5.0.0, cosmiconfig@^5.1.0, cosmiconfig@^5.2.1: version "5.2.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== @@ -7461,13 +6710,6 @@ create-ecdh@^4.0.0: bn.js "^4.1.0" elliptic "^6.0.0" -create-error-class@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" - integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= - dependencies: - capture-stack-trace "^1.0.0" - create-hash@^1.1.0, create-hash@^1.1.2: version "1.2.0" resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" @@ -7514,14 +6756,7 @@ cross-fetch@3.0.4, cross-fetch@^3.0.4: node-fetch "2.6.0" whatwg-fetch "3.0.0" -cross-spawn-promise@^0.10.1: - version "0.10.2" - resolved "https://registry.npmjs.org/cross-spawn-promise/-/cross-spawn-promise-0.10.2.tgz#0e6338149caf53a6d557ac5c65efb3086d8704ac" - integrity sha512-74PXJf6DYaab2klRS+D+9qxKJL1Weo3/ao9OPoH6NFzxtINSa/HE2mcyAPu1fpEmRTPD4Gdmpg3xEXQSgI8lpg== - dependencies: - cross-spawn "^5.1.0" - -cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@6.0.5, cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -7541,7 +6776,7 @@ cross-spawn@7.0.1, cross-spawn@^7.0.0, cross-spawn@^7.0.1: shebang-command "^2.0.0" which "^2.0.1" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= @@ -7550,6 +6785,15 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -7567,11 +6811,6 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-random-string@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" - integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= - crypto-random-string@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" @@ -7822,7 +7061,7 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@~0.3.6: resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssom@^0.4.1, cssom@^0.4.4: +cssom@^0.4.4: version "0.4.4" resolved "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== @@ -7834,13 +7073,6 @@ cssstyle@^1.0.0: dependencies: cssom "0.3.x" -cssstyle@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz#e4c44debccd6b7911ed617a4395e5754bba59992" - integrity sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA== - dependencies: - cssom "~0.3.6" - cssstyle@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" @@ -7908,35 +7140,6 @@ cypress@*, cypress@^4.2.0: url "0.11.0" yauzl "2.10.0" -cz-conventional-changelog@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.0.1.tgz#b1f207ae050355e7ada65aad5c52e9de3d0c8e5b" - integrity sha512-7KASIwB8/ClEyCRvQrCPbN7WkQnUSjSSVNyPM+gDJ0jskLi8h8N2hrdpyeCk7fIqKMRzziqVSOBTB8yyLTMHGQ== - dependencies: - chalk "^2.4.1" - conventional-commit-types "^2.0.0" - lodash.map "^4.5.1" - longest "^2.0.1" - right-pad "^1.0.1" - word-wrap "^1.0.3" - optionalDependencies: - "@commitlint/load" ">6.1.1" - -cz-conventional-changelog@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.1.0.tgz#1e004a4f507531347a5f78ab4ed65c3ff693fc97" - integrity sha512-SCwPPOF+7qMh1DZkJhrwaxCvZzPaz2E9BwQzcZwBuHlpcJj9zzz7K5vADQRhHuxStaHZFSLbDlZEdcls4bKu7Q== - dependencies: - chalk "^2.4.1" - commitizen "^4.0.3" - conventional-commit-types "^3.0.0" - lodash.map "^4.5.1" - longest "^2.0.1" - right-pad "^1.0.1" - word-wrap "^1.0.3" - optionalDependencies: - "@commitlint/load" ">6.1.1" - d3-dispatch@1: version "1.0.6" resolved "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" @@ -7990,7 +7193,7 @@ dashify@^2.0.0: resolved "https://registry.npmjs.org/dashify/-/dashify-2.0.0.tgz#fff270ca2868ca427fee571de35691d6e437a648" integrity sha512-hpA5C/YrPjucXypHPPc0oJ1l9Hf6wWbiOL7Ik42cxnsUOhWiCB/fylKbKqqJalW9FgkNQCw16YO8uW9Hs0Iy1A== -data-urls@^1.0.0, data-urls@^1.1.0: +data-urls@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== @@ -8042,7 +7245,7 @@ debug@3.1.0, debug@=3.1.0: dependencies: ms "2.0.0" -debug@4, debug@4.1.1, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@4.1.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -8069,7 +7272,7 @@ decamelize-keys@^1.0.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.1.0, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -8091,7 +7294,7 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -dedent@0.7.0, dedent@^0.7.0: +dedent@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= @@ -8113,7 +7316,7 @@ deep-extend@^0.6.0: resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= @@ -8257,12 +7460,7 @@ detect-file@^1.0.0: resolved "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-indent@6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" - integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== - -detect-indent@^5.0.0, detect-indent@~5.0.0: +detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= @@ -8272,11 +7470,6 @@ detect-libc@^1.0.2: resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= - detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -8303,7 +7496,7 @@ detect-port@^1.3.0: address "^1.0.1" debug "^2.6.0" -dezalgo@^1.0.0, dezalgo@~1.0.3: +dezalgo@^1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= @@ -8359,7 +7552,7 @@ dir-glob@^2.0.0, dir-glob@^2.2.2: dependencies: path-type "^3.0.0" -dir-glob@^3.0.0, dir-glob@^3.0.1: +dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== @@ -8566,7 +7759,7 @@ dot-prop@^3.0.0: dependencies: is-obj "^1.0.0" -dot-prop@^4.1.0, dot-prop@^4.2.0: +dot-prop@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== @@ -8599,11 +7792,6 @@ dotenv-webpack@^1.7.0: dependencies: dotenv-defaults "^1.0.2" -dotenv@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" - integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow== - dotenv@^6.2.0: version "6.2.0" resolved "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" @@ -8614,13 +7802,6 @@ dotenv@^8.0.0: resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== -duplexer2@~0.1.0: - version "0.1.4" - resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= - dependencies: - readable-stream "^2.0.2" - duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -8649,11 +7830,6 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -editor@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" - integrity sha1-YMf4e9YrzGqJT6jM1q+3gjok90I= - ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -8768,14 +7944,6 @@ entities@^2.0.0, entities@~2.0.0: resolved "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== -env-ci@^5.0.0: - version "5.0.2" - resolved "https://registry.npmjs.org/env-ci/-/env-ci-5.0.2.tgz#48b6687f8af8cdf5e31b8fcf2987553d085249d9" - integrity sha512-Xc41mKvjouTXD3Oy9AqySz1IeyvJvHZ20Twf5ZLYbNpPPIuCnL/qHCmNlD01LoNy0JTunw9HPYVptD19Ac7Mbw== - dependencies: - execa "^4.0.0" - java-properties "^1.0.0" - env-paths@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" @@ -8908,7 +8076,7 @@ escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@^1.11.1, escodegen@^1.14.1, escodegen@^1.9.1: +escodegen@^1.14.1, escodegen@^1.9.1: version "1.14.1" resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== @@ -9020,6 +8188,11 @@ eslint-plugin-notice@^0.9.10: lodash "^4.17.15" metric-lcs "^0.1.2" +eslint-plugin-react-hooks@^4.0.0: + version "4.0.4" + resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.4.tgz#aed33b4254a41b045818cacb047b81e6df27fa58" + integrity sha512-equAdEIsUETLFNCmmCkiCGq6rkSK5MoJhXFPFYeUebcjKgBmWWcgVOqZyQC8Bv1BwVCnTq9tBxgJFgAJTWoJtA== + eslint-plugin-react@^7.12.4: version "7.19.0" resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz#6d08f9673628aa69c5559d33489e855d83551666" @@ -9061,27 +8234,34 @@ eslint-utils@^1.4.3: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" + integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA== + dependencies: + eslint-visitor-keys "^1.1.0" + eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@^6.8.0: - version "6.8.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== +eslint@^7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" + integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" + chalk "^4.0.0" + cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" eslint-scope "^5.0.0" - eslint-utils "^1.4.3" + eslint-utils "^2.0.0" eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" + espree "^7.0.0" + esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" @@ -9094,17 +8274,16 @@ eslint@^6.8.0: is-glob "^4.0.0" js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" + levn "^0.4.1" lodash "^4.17.14" minimatch "^3.0.4" - mkdirp "^0.5.1" natural-compare "^1.4.0" - optionator "^0.8.3" + optionator "^0.9.1" progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" table "^5.2.3" text-table "^0.2.0" v8-compile-cache "^2.0.3" @@ -9114,10 +8293,10 @@ esm@^3.2.25: resolved "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== +espree@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/espree/-/espree-7.0.0.tgz#8a7a60f218e69f120a842dc24c5a88aa7748a74e" + integrity sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw== dependencies: acorn "^7.1.1" acorn-jsx "^5.2.0" @@ -9128,12 +8307,12 @@ esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1: - version "1.1.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.1.0.tgz#c5c0b66f383e7656404f86b31334d72524eddb48" - integrity sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q== +esquery@^1.2.0: + version "1.3.1" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== dependencies: - estraverse "^4.0.0" + estraverse "^5.1.0" esrecurse@^4.1.0: version "4.2.1" @@ -9142,11 +8321,16 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== +estraverse@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" + integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== + estree-walker@^0.6.0, estree-walker@^0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" @@ -9233,7 +8417,7 @@ execa@1.0.0, execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@3.4.0, execa@^3.2.0, execa@^3.4.0: +execa@3.4.0, execa@^3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== @@ -9249,19 +8433,6 @@ execa@3.4.0, execa@^3.2.0, execa@^3.4.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/execa/-/execa-4.0.0.tgz#7f37d6ec17f09e6b8fc53288611695b6d12b9daf" @@ -9319,18 +8490,6 @@ expect-ct@0.2.0: resolved "https://registry.npmjs.org/expect-ct/-/expect-ct-0.2.0.tgz#3a54741b6ed34cc7a93305c605f63cd268a54a62" integrity sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g== -expect@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/expect/-/expect-25.1.0.tgz#7e8d7b06a53f7d66ec927278db3304254ee683ee" - integrity sha512-wqHzuoapQkhc3OKPlrpetsfueuEiMf3iWh0R8+duCu9PIjXoP7HgD5aeypwTnXUAjC8aMsiVDaWwlbJ1RlQ38g== - dependencies: - "@jest/types" "^25.1.0" - ansi-styles "^4.0.0" - jest-get-type "^25.1.0" - jest-matcher-utils "^25.1.0" - jest-message-util "^25.1.0" - jest-regex-util "^25.1.0" - expect@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/expect/-/expect-26.0.1.tgz#18697b9611a7e2725e20ba3ceadda49bc9865421" @@ -9696,20 +8855,7 @@ find-cache-dir@^3.0.0, find-cache-dir@^3.2.0: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-node-modules@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.0.0.tgz#5db1fb9e668a3d451db3d618cd167cdd59e41b69" - integrity sha512-8MWIBRgJi/WpjjfVXumjPKCtmQ10B+fjx6zmSA+770GMJirLhWIzg8l763rhjl9xaeaHbnxPNRQKq2mgMhr+aw== - dependencies: - findup-sync "^3.0.0" - merge "^1.2.1" - -find-npm-prefix@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf" - integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA== - -find-root@1.1.0, find-root@^1.1.0: +find-root@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== @@ -9744,7 +8890,7 @@ find-up@^2.0.0, find-up@^2.1.0: dependencies: locate-path "^2.0.0" -find-versions@^3.0.0, find-versions@^3.2.0: +find-versions@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== @@ -9787,9 +8933,9 @@ flat-cache@^2.0.1: write "1.0.3" flatted@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" - integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + version "2.0.2" + resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== flush-write-stream@^1.0.0: version "1.1.1" @@ -9952,15 +9098,7 @@ fresh@0.5.2: resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -from2@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz#88413baaa5f9a597cfde9221d86986cd3c061dfd" - integrity sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0= - dependencies: - inherits "~2.0.1" - readable-stream "~1.1.10" - -from2@^2.1.0, from2@^2.3.0: +from2@^2.1.0: version "2.3.0" resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= @@ -10022,16 +9160,7 @@ fs-minipass@^2.0.0: dependencies: minipass "^3.0.0" -fs-vacuum@^1.2.10, fs-vacuum@~1.2.10: - version "1.2.10" - resolved "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" - integrity sha1-t2Kb7AekAxolSP35n17PHMizHjY= - dependencies: - graceful-fs "^4.1.2" - path-is-inside "^1.0.1" - rimraf "^2.5.2" - -fs-write-stream-atomic@^1.0.8, fs-write-stream-atomic@~1.0.10: +fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= @@ -10119,28 +9248,6 @@ gensync@^1.0.0-beta.1: resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== -gentle-fs@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.3.0.tgz#13538db5029400f98684be4894e8a7d8f0d1ea7f" - integrity sha512-3k2CgAmPxuz7S6nKK+AqFE2AdM1QuwqKLPKzIET3VRwK++3q96MsNFobScDjlCrq97ZJ8y5R725MOlm6ffUCjg== - dependencies: - aproba "^1.1.2" - chownr "^1.1.2" - cmd-shim "^3.0.3" - fs-vacuum "^1.2.10" - graceful-fs "^4.1.11" - iferr "^0.1.5" - infer-owner "^1.0.4" - mkdirp "^0.5.1" - path-is-inside "^1.0.2" - read-cmd-shim "^1.0.1" - slide "^1.1.6" - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/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.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -10180,11 +9287,6 @@ get-port@^5.1.1: resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== -get-stdin@7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" - integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== - get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -10195,11 +9297,6 @@ get-stdin@^6.0.0: resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - get-stream@^4.0.0, get-stream@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -10238,18 +9335,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -git-log-parser@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz#2e6a4c1b13fc00028207ba795a7ac31667b9fd4a" - integrity sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo= - dependencies: - argv-formatter "~1.0.0" - spawn-error-forwarder "~1.0.0" - split2 "~1.0.0" - stream-combiner2 "~1.1.1" - through2 "~2.0.0" - traverse "~0.6.6" - git-raw-commits@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.0.tgz#d92addf74440c14bcc5c83ecce3fb7f8a79118b5" @@ -10261,17 +9346,6 @@ git-raw-commits@2.0.0: split2 "^2.0.0" through2 "^2.0.0" -git-raw-commits@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.3.tgz#f040e67b8445962d4d168903a9e84c4240c17655" - integrity sha512-SoSsFL5lnixVzctGEi2uykjA7B5I0AhO9x6kdzvGRHbxsa6JSEgrgy1esRKsfOKE1cgyOJ/KDR2Trxu157sb8w== - dependencies: - dargs "^4.0.1" - lodash.template "^4.0.2" - meow "^5.0.0" - split2 "^2.0.0" - through2 "^3.0.0" - git-remote-origin-url@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" @@ -10345,18 +9419,6 @@ glob-to-regexp@^0.3.0: resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@7.1.4: - version "7.1.4" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== - 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" - glob@7.1.6, glob@^7.0.0, glob@^7.0.3, 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.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -10369,7 +9431,7 @@ glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glo once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^0.1.0, global-dirs@^0.1.1: +global-dirs@^0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= @@ -10529,23 +9591,6 @@ good-listener@^1.2.2: dependencies: delegate "^3.1.2" -got@^6.7.1: - version "6.7.1" - resolved "https://registry.npmjs.org/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" - integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= - dependencies: - create-error-class "^3.0.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-redirect "^1.0.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - lowercase-keys "^1.0.0" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - unzip-response "^2.0.1" - url-parse-lax "^1.0.0" - got@^9.6.0: version "9.6.0" resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -10563,7 +9608,7 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2: version "4.2.3" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== @@ -10740,7 +9785,7 @@ has-symbols@^1.0.0, has-symbols@^1.0.1: resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== -has-unicode@^2.0.0, has-unicode@^2.0.1, has-unicode@~2.0.1: +has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= @@ -10915,28 +9960,16 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -hook-std@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz#ff9aafdebb6a989a354f729bb6445cf4a3a7077c" - integrity sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g== - hoopy@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== -hosted-git-info@^2.1.4, hosted-git-info@^2.7.1, hosted-git-info@^2.8.8: +hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: version "2.8.8" resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== -hosted-git-info@^3.0.0: - version "3.0.4" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.4.tgz#be4973eb1fd2737b11c9c7c19380739bb249f60d" - integrity sha512-4oT62d2jwSDBbLLFLZE+1vPuQ1h8p9wjrJ8Mqx5TjsyWmBMV5B13eJqn8pvluqubLf3cJPTfiYCIwNwDNmzScQ== - dependencies: - lru-cache "^5.1.1" - hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -11118,15 +10151,6 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy-agent@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - http-proxy-middleware@0.19.1: version "0.19.1" resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" @@ -11168,14 +10192,6 @@ https-proxy-agent@^2.2.3: agent-base "^4.3.0" debug "^3.1.0" -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -11250,11 +10266,6 @@ iferr@^0.1.5: resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -iferr@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d" - integrity sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg== - ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -11389,7 +10400,7 @@ infer-owner@^1.0.3, infer-owner@^1.0.4: resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== -inflight@^1.0.4, inflight@~1.0.6: +inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= @@ -11542,14 +10553,6 @@ interpret@^2.0.0: resolved "https://registry.npmjs.org/interpret/-/interpret-2.0.0.tgz#b783ffac0b8371503e9ab39561df223286aa5433" integrity sha512-e0/LknJ8wpMMhTiWcjivB+ESwIuvHnBSlBbmP/pSb8CQJldoj1p2qv7xGZ/+BtbTziYRFSz8OsvdbiX45LtYQA== -into-stream@^5.0.0: - version "5.1.1" - resolved "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz#f9a20a348a11f3c13face22763f2d02e127f4db8" - integrity sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA== - dependencies: - from2 "^2.3.0" - p-is-promise "^3.0.0" - invariant@^2.2.2, invariant@^2.2.3, invariant@^2.2.4: version "2.2.4" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -11557,16 +10560,6 @@ invariant@^2.2.2, invariant@^2.2.3, invariant@^2.2.4: dependencies: loose-envify "^1.0.0" -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -11673,20 +10666,6 @@ is-ci@2.0.0, is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-ci@^1.0.10: - version "1.2.1" - resolved "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" - integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== - dependencies: - ci-info "^1.5.0" - -is-cidr@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/is-cidr/-/is-cidr-3.1.0.tgz#72e233d8e1c4cd1d3f11713fcce3eba7b0e3476f" - integrity sha512-3kxTForpuj8O4iHn0ocsn1jxRm5VYm60GDghK6HXmpn4IyZOoRy9/GmdjFA2yEMqw91TB1/K3bFTuI7FlFNR1g== - dependencies: - cidr-regex "^2.0.10" - is-color-stop@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" @@ -11844,7 +10823,7 @@ is-in-browser@^1.0.2, is-in-browser@^1.1.3: resolved "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU= -is-installed-globally@0.1.0, is-installed-globally@^0.1.0: +is-installed-globally@0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= @@ -11875,11 +10854,6 @@ is-module@^1.0.0: resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= -is-npm@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" - integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= - is-npm@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" @@ -11979,11 +10953,6 @@ is-promise@^2.1.0: resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= -is-redirect@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= - is-reference@^1.1.2: version "1.1.4" resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz#3f95849886ddb70256a3e6d062b1a68c13c51427" @@ -12015,11 +10984,6 @@ is-resolvable@^1.0.0: resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== -is-retry-allowed@^1.0.0: - version "1.2.0" - resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== - is-root@2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" @@ -12037,7 +11001,7 @@ is-ssh@^1.3.0: dependencies: protocols "^1.1.0" -is-stream@^1.0.0, is-stream@^1.1.0: +is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -12085,7 +11049,7 @@ is-unc-path@^1.0.0: dependencies: unc-path-regex "^0.1.2" -is-utf8@^0.2.0, is-utf8@^0.2.1: +is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= @@ -12167,17 +11131,6 @@ isstream@~0.1.2: resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -issue-parser@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz#b1edd06315d4f2044a9755daf85fdafde9b4014a" - integrity sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA== - dependencies: - lodash.capitalize "^4.2.1" - lodash.escaperegexp "^4.1.2" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.uniqby "^4.7.0" - istanbul-lib-coverage@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" @@ -12214,14 +11167,6 @@ istanbul-lib-source-maps@^4.0.0: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.0.tgz#d4d16d035db99581b6194e119bbf36c963c5eb70" - integrity sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - istanbul-reports@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" @@ -12248,20 +11193,6 @@ iterate-value@^1.0.0: es-get-iterator "^1.0.2" iterate-iterator "^1.0.1" -java-properties@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211" - integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ== - -jest-changed-files@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-25.1.0.tgz#73dae9a7d9949fdfa5c278438ce8f2ff3ec78131" - integrity sha512-bdL1aHjIVy3HaBO3eEQeemGttsq1BDlHgWcOjEOIAcga7OOEGWHD2WSu8HhL7I1F0mFFyci8VKU4tRNk+qtwDA== - dependencies: - "@jest/types" "^25.1.0" - execa "^3.2.0" - throat "^5.0.0" - jest-changed-files@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.0.1.tgz#1334630c6a1ad75784120f39c3aa9278e59f349f" @@ -12271,25 +11202,6 @@ jest-changed-files@^26.0.1: execa "^4.0.0" throat "^5.0.0" -jest-cli@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-25.1.0.tgz#75f0b09cf6c4f39360906bf78d580be1048e4372" - integrity sha512-p+aOfczzzKdo3AsLJlhs8J5EW6ffVidfSZZxXedJ0mHPBOln1DccqFmGCoO8JWd4xRycfmwy1eoQkMsF8oekPg== - dependencies: - "@jest/core" "^25.1.0" - "@jest/test-result" "^25.1.0" - "@jest/types" "^25.1.0" - chalk "^3.0.0" - exit "^0.1.2" - import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^25.1.0" - jest-util "^25.1.0" - jest-validate "^25.1.0" - prompts "^2.0.1" - realpath-native "^1.1.0" - yargs "^15.0.0" - jest-cli@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-26.0.1.tgz#3a42399a4cbc96a519b99ad069a117d955570cac" @@ -12309,29 +11221,6 @@ jest-cli@^26.0.1: prompts "^2.0.1" yargs "^15.3.1" -jest-config@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-config/-/jest-config-25.1.0.tgz#d114e4778c045d3ef239452213b7ad3ec1cbea90" - integrity sha512-tLmsg4SZ5H7tuhBC5bOja0HEblM0coS3Wy5LTCb2C8ZV6eWLewHyK+3qSq9Bi29zmWQ7ojdCd3pxpx4l4d2uGw== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^25.1.0" - "@jest/types" "^25.1.0" - babel-jest "^25.1.0" - chalk "^3.0.0" - glob "^7.1.1" - jest-environment-jsdom "^25.1.0" - jest-environment-node "^25.1.0" - jest-get-type "^25.1.0" - jest-jasmine2 "^25.1.0" - jest-regex-util "^25.1.0" - jest-resolve "^25.1.0" - jest-util "^25.1.0" - jest-validate "^25.1.0" - micromatch "^4.0.2" - pretty-format "^25.1.0" - realpath-native "^1.1.0" - jest-config@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-config/-/jest-config-26.0.1.tgz#096a3d4150afadf719d1fab00e9a6fb2d6d67507" @@ -12383,13 +11272,6 @@ jest-diff@^26.0.1: jest-get-type "^26.0.0" pretty-format "^26.0.1" -jest-docblock@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-25.1.0.tgz#0f44bea3d6ca6dfc38373d465b347c8818eccb64" - integrity sha512-370P/mh1wzoef6hUKiaMcsPtIapY25suP6JqM70V9RJvdKLrV4GaGbfUseUVk4FZJw4oTZ1qSCJNdrClKt5JQA== - dependencies: - detect-newline "^3.0.0" - jest-docblock@^26.0.0: version "26.0.0" resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" @@ -12397,17 +11279,6 @@ jest-docblock@^26.0.0: dependencies: detect-newline "^3.0.0" -jest-each@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-each/-/jest-each-25.1.0.tgz#a6b260992bdf451c2d64a0ccbb3ac25e9b44c26a" - integrity sha512-R9EL8xWzoPySJ5wa0DXFTj7NrzKpRD40Jy+zQDp3Qr/2QmevJgkN9GqioCGtAJ2bW9P/MQRznQHQQhoeAyra7A== - dependencies: - "@jest/types" "^25.1.0" - chalk "^3.0.0" - jest-get-type "^25.1.0" - jest-util "^25.1.0" - pretty-format "^25.1.0" - jest-each@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-each/-/jest-each-26.0.1.tgz#633083061619302fc90dd8f58350f9d77d67be04" @@ -12419,18 +11290,6 @@ jest-each@^26.0.1: jest-util "^26.0.1" pretty-format "^26.0.1" -jest-environment-jsdom@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-25.1.0.tgz#6777ab8b3e90fd076801efd3bff8e98694ab43c3" - integrity sha512-ILb4wdrwPAOHX6W82GGDUiaXSSOE274ciuov0lztOIymTChKFtC02ddyicRRCdZlB5YSrv3vzr1Z5xjpEe1OHQ== - dependencies: - "@jest/environment" "^25.1.0" - "@jest/fake-timers" "^25.1.0" - "@jest/types" "^25.1.0" - jest-mock "^25.1.0" - jest-util "^25.1.0" - jsdom "^15.1.1" - jest-environment-jsdom@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.0.1.tgz#217690852e5bdd7c846a4e3b50c8ffd441dfd249" @@ -12443,17 +11302,6 @@ jest-environment-jsdom@^26.0.1: jest-util "^26.0.1" jsdom "^16.2.2" -jest-environment-node@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-25.1.0.tgz#797bd89b378cf0bd794dc8e3dca6ef21126776db" - integrity sha512-U9kFWTtAPvhgYY5upnH9rq8qZkj6mYLup5l1caAjjx9uNnkLHN2xgZy5mo4SyLdmrh/EtB9UPpKFShvfQHD0Iw== - dependencies: - "@jest/environment" "^25.1.0" - "@jest/fake-timers" "^25.1.0" - "@jest/types" "^25.1.0" - jest-mock "^25.1.0" - jest-util "^25.1.0" - jest-environment-node@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.0.1.tgz#584a9ff623124ff6eeb49e0131b5f7612b310b13" @@ -12481,11 +11329,6 @@ jest-fetch-mock@^3.0.3: cross-fetch "^3.0.4" promise-polyfill "^8.1.3" -jest-get-type@^24.9.0: - version "24.9.0" - resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" - integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== - jest-get-type@^25.1.0: version "25.1.0" resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.1.0.tgz#1cfe5fc34f148dc3a8a3b7275f6b9ce9e2e8a876" @@ -12501,24 +11344,6 @@ jest-get-type@^26.0.0: resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg== -jest-haste-map@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.1.0.tgz#ae12163d284f19906260aa51fd405b5b2e5a4ad3" - integrity sha512-/2oYINIdnQZAqyWSn1GTku571aAfs8NxzSErGek65Iu5o8JYb+113bZysRMcC/pjE5v9w0Yz+ldbj9NxrFyPyw== - dependencies: - "@jest/types" "^25.1.0" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.3" - jest-serializer "^25.1.0" - jest-util "^25.1.0" - jest-worker "^25.1.0" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.1.2" - jest-haste-map@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.0.1.tgz#40dcc03c43ac94d25b8618075804d09cd5d49de7" @@ -12539,29 +11364,6 @@ jest-haste-map@^26.0.1: optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-25.1.0.tgz#681b59158a430f08d5d0c1cce4f01353e4b48137" - integrity sha512-GdncRq7jJ7sNIQ+dnXvpKO2MyP6j3naNK41DTTjEAhLEdpImaDA9zSAZwDhijjSF/D7cf4O5fdyUApGBZleaEg== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^25.1.0" - "@jest/source-map" "^25.1.0" - "@jest/test-result" "^25.1.0" - "@jest/types" "^25.1.0" - chalk "^3.0.0" - co "^4.6.0" - expect "^25.1.0" - is-generator-fn "^2.0.0" - jest-each "^25.1.0" - jest-matcher-utils "^25.1.0" - jest-message-util "^25.1.0" - jest-runtime "^25.1.0" - jest-snapshot "^25.1.0" - jest-util "^25.1.0" - pretty-format "^25.1.0" - throat "^5.0.0" - jest-jasmine2@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.0.1.tgz#947c40ee816636ba23112af3206d6fa7b23c1c1c" @@ -12585,25 +11387,6 @@ jest-jasmine2@^26.0.1: pretty-format "^26.0.1" throat "^5.0.0" -jest-junit@^10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/jest-junit/-/jest-junit-10.0.0.tgz#c94b91c24920a327c9d2a075e897b2dba4af494b" - integrity sha512-dbOVRyxHprdSpwSAR9/YshLwmnwf+RSl5hf0kCGlhAcEeZY9aRqo4oNmaT0tLC16Zy9D0zekDjWkjHGjXlglaQ== - dependencies: - jest-validate "^24.9.0" - mkdirp "^0.5.1" - strip-ansi "^5.2.0" - uuid "^3.3.3" - xml "^1.0.1" - -jest-leak-detector@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-25.1.0.tgz#ed6872d15aa1c72c0732d01bd073dacc7c38b5c6" - integrity sha512-3xRI264dnhGaMHRvkFyEKpDeaRzcEBhyNrOG5oT8xPxOyUAblIAQnpiR3QXu4wDor47MDTiHbiFcbypdLcLW5w== - dependencies: - jest-get-type "^25.1.0" - pretty-format "^25.1.0" - jest-leak-detector@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.0.1.tgz#79b19ab3f41170e0a78eb8fa754a116d3447fb8c" @@ -12632,20 +11415,6 @@ jest-matcher-utils@^26.0.1: jest-get-type "^26.0.0" pretty-format "^26.0.1" -jest-message-util@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-25.1.0.tgz#702a9a5cb05c144b9aa73f06e17faa219389845e" - integrity sha512-Nr/Iwar2COfN22aCqX0kCVbXgn8IBm9nWf4xwGr5Olv/KZh0CZ32RKgZWMVDXGdOahicM10/fgjdimGNX/ttCQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/test-result" "^25.1.0" - "@jest/types" "^25.1.0" - "@types/stack-utils" "^1.0.1" - chalk "^3.0.0" - micromatch "^4.0.2" - slash "^3.0.0" - stack-utils "^1.0.1" - jest-message-util@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.0.1.tgz#07af1b42fc450b4cc8e90e4c9cef11b33ce9b0ac" @@ -12660,13 +11429,6 @@ jest-message-util@^26.0.1: slash "^3.0.0" stack-utils "^2.0.2" -jest-mock@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-25.1.0.tgz#411d549e1b326b7350b2e97303a64715c28615fd" - integrity sha512-28/u0sqS+42vIfcd1mlcg4ZVDmSUYuNvImP4X2lX5hRMLW+CN0BeiKVD4p+ujKKbSPKd3rg/zuhCF+QBLJ4vag== - dependencies: - "@jest/types" "^25.1.0" - jest-mock@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-26.0.1.tgz#7fd1517ed4955397cf1620a771dc2d61fad8fd40" @@ -12679,25 +11441,11 @@ jest-pnp-resolver@^1.2.1: resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== -jest-regex-util@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.1.0.tgz#efaf75914267741838e01de24da07b2192d16d87" - integrity sha512-9lShaDmDpqwg+xAd73zHydKrBbbrIi08Kk9YryBEBybQFg/lBWR/2BDjjiSE7KIppM9C5+c03XiDaZ+m4Pgs1w== - jest-regex-util@^26.0.0: version "26.0.0" resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-resolve-dependencies@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-25.1.0.tgz#8a1789ec64eb6aaa77fd579a1066a783437e70d2" - integrity sha512-Cu/Je38GSsccNy4I2vL12ZnBlD170x2Oh1devzuM9TLH5rrnLW1x51lN8kpZLYTvzx9j+77Y5pqBaTqfdzVzrw== - dependencies: - "@jest/types" "^25.1.0" - jest-regex-util "^25.1.0" - jest-snapshot "^25.1.0" - jest-resolve-dependencies@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.0.1.tgz#607ba7ccc32151d185a477cff45bf33bce417f0b" @@ -12707,17 +11455,6 @@ jest-resolve-dependencies@^26.0.1: jest-regex-util "^26.0.0" jest-snapshot "^26.0.1" -jest-resolve@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.1.0.tgz#23d8b6a4892362baf2662877c66aa241fa2eaea3" - integrity sha512-XkBQaU1SRCHj2Evz2Lu4Czs+uIgJXWypfO57L7JYccmAXv4slXA6hzNblmcRmf7P3cQ1mE7fL3ABV6jAwk4foQ== - dependencies: - "@jest/types" "^25.1.0" - browser-resolve "^1.11.3" - chalk "^3.0.0" - jest-pnp-resolver "^1.2.1" - realpath-native "^1.1.0" - jest-resolve@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.0.1.tgz#21d1ee06f9ea270a343a8893051aeed940cde736" @@ -12732,31 +11469,6 @@ jest-resolve@^26.0.1: resolve "^1.17.0" slash "^3.0.0" -jest-runner@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-25.1.0.tgz#fef433a4d42c89ab0a6b6b268e4a4fbe6b26e812" - integrity sha512-su3O5fy0ehwgt+e8Wy7A8CaxxAOCMzL4gUBftSs0Ip32S0epxyZPDov9Znvkl1nhVOJNf4UwAsnqfc3plfQH9w== - dependencies: - "@jest/console" "^25.1.0" - "@jest/environment" "^25.1.0" - "@jest/test-result" "^25.1.0" - "@jest/types" "^25.1.0" - chalk "^3.0.0" - exit "^0.1.2" - graceful-fs "^4.2.3" - jest-config "^25.1.0" - jest-docblock "^25.1.0" - jest-haste-map "^25.1.0" - jest-jasmine2 "^25.1.0" - jest-leak-detector "^25.1.0" - jest-message-util "^25.1.0" - jest-resolve "^25.1.0" - jest-runtime "^25.1.0" - jest-util "^25.1.0" - jest-worker "^25.1.0" - source-map-support "^0.5.6" - throat "^5.0.0" - jest-runner@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-26.0.1.tgz#ea03584b7ae4bacfb7e533d680a575a49ae35d50" @@ -12782,37 +11494,6 @@ jest-runner@^26.0.1: source-map-support "^0.5.6" throat "^5.0.0" -jest-runtime@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-25.1.0.tgz#02683218f2f95aad0f2ec1c9cdb28c1dc0ec0314" - integrity sha512-mpPYYEdbExKBIBB16ryF6FLZTc1Rbk9Nx0ryIpIMiDDkOeGa0jQOKVI/QeGvVGlunKKm62ywcioeFVzIbK03bA== - dependencies: - "@jest/console" "^25.1.0" - "@jest/environment" "^25.1.0" - "@jest/source-map" "^25.1.0" - "@jest/test-result" "^25.1.0" - "@jest/transform" "^25.1.0" - "@jest/types" "^25.1.0" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.3" - jest-config "^25.1.0" - jest-haste-map "^25.1.0" - jest-message-util "^25.1.0" - jest-mock "^25.1.0" - jest-regex-util "^25.1.0" - jest-resolve "^25.1.0" - jest-snapshot "^25.1.0" - jest-util "^25.1.0" - jest-validate "^25.1.0" - realpath-native "^1.1.0" - slash "^3.0.0" - strip-bom "^4.0.0" - yargs "^15.0.0" - jest-runtime@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.0.1.tgz#a121a6321235987d294168e282d52b364d7d3f89" @@ -12845,11 +11526,6 @@ jest-runtime@^26.0.1: strip-bom "^4.0.0" yargs "^15.3.1" -jest-serializer@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.1.0.tgz#73096ba90e07d19dec4a0c1dd89c355e2f129e5d" - integrity sha512-20Wkq5j7o84kssBwvyuJ7Xhn7hdPeTXndnwIblKDR2/sy1SUm6rWWiG9kSCgJPIfkDScJCIsTtOKdlzfIHOfKA== - jest-serializer@^26.0.0: version "26.0.0" resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.0.0.tgz#f6c521ddb976943b93e662c0d4d79245abec72a3" @@ -12857,25 +11533,6 @@ jest-serializer@^26.0.0: dependencies: graceful-fs "^4.2.4" -jest-snapshot@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-25.1.0.tgz#d5880bd4b31faea100454608e15f8d77b9d221d9" - integrity sha512-xZ73dFYN8b/+X2hKLXz4VpBZGIAn7muD/DAg+pXtDzDGw3iIV10jM7WiHqhCcpDZfGiKEj7/2HXAEPtHTj0P2A== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^25.1.0" - chalk "^3.0.0" - expect "^25.1.0" - jest-diff "^25.1.0" - jest-get-type "^25.1.0" - jest-matcher-utils "^25.1.0" - jest-message-util "^25.1.0" - jest-resolve "^25.1.0" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - pretty-format "^25.1.0" - semver "^7.1.1" - jest-snapshot@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.0.1.tgz#1baa942bd83d47b837a84af7fcf5fd4a236da399" @@ -12897,16 +11554,6 @@ jest-snapshot@^26.0.1: pretty-format "^26.0.1" semver "^7.3.2" -jest-util@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-util/-/jest-util-25.1.0.tgz#7bc56f7b2abd534910e9fa252692f50624c897d9" - integrity sha512-7did6pLQ++87Qsj26Fs/TIwZMUFBXQ+4XXSodRNy3luch2DnRXsSnmpVtxxQ0Yd6WTipGpbhh2IFP1mq6/fQGw== - dependencies: - "@jest/types" "^25.1.0" - chalk "^3.0.0" - is-ci "^2.0.0" - mkdirp "^0.5.1" - jest-util@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.0.1.tgz#72c4c51177b695fdd795ca072a6f94e3d7cef00a" @@ -12918,30 +11565,6 @@ jest-util@^26.0.1: is-ci "^2.0.0" make-dir "^3.0.0" -jest-validate@^24.9.0: - version "24.9.0" - resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" - integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== - dependencies: - "@jest/types" "^24.9.0" - camelcase "^5.3.1" - chalk "^2.0.1" - jest-get-type "^24.9.0" - leven "^3.1.0" - pretty-format "^24.9.0" - -jest-validate@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-25.1.0.tgz#1469fa19f627bb0a9a98e289f3e9ab6a668c732a" - integrity sha512-kGbZq1f02/zVO2+t1KQGSVoCTERc5XeObLwITqC6BTRH3Adv7NZdYqCpKIZLUgpLXf2yISzQ465qOZpul8abXA== - dependencies: - "@jest/types" "^25.1.0" - camelcase "^5.3.1" - chalk "^3.0.0" - jest-get-type "^25.1.0" - leven "^3.1.0" - pretty-format "^25.1.0" - jest-validate@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-26.0.1.tgz#a62987e1da5b7f724130f904725e22f4e5b2e23c" @@ -12954,18 +11577,6 @@ jest-validate@^26.0.1: leven "^3.1.0" pretty-format "^26.0.1" -jest-watcher@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-25.1.0.tgz#97cb4a937f676f64c9fad2d07b824c56808e9806" - integrity sha512-Q9eZ7pyaIr6xfU24OeTg4z1fUqBF/4MP6J801lyQfg7CsnZ/TCzAPvCfckKdL5dlBBEKBeHV0AdyjFZ5eWj4ig== - dependencies: - "@jest/test-result" "^25.1.0" - "@jest/types" "^25.1.0" - ansi-escapes "^4.2.1" - chalk "^3.0.0" - jest-util "^25.1.0" - string-length "^3.1.0" - jest-watcher@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.0.1.tgz#5b5e3ebbdf10c240e22a98af66d645631afda770" @@ -12994,15 +11605,6 @@ jest-worker@^26.0.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest/-/jest-25.1.0.tgz#b85ef1ddba2fdb00d295deebbd13567106d35be9" - integrity sha512-FV6jEruneBhokkt9MQk0WUFoNTwnF76CLXtwNMfsc0um0TlB/LG2yxUd0KqaFjEJ9laQmVWQWS0sG/t2GsuI0w== - dependencies: - "@jest/core" "^25.1.0" - import-local "^3.0.2" - jest-cli "^25.1.0" - jest@^26.0.1: version "26.0.1" resolved "https://registry.npmjs.org/jest/-/jest-26.0.1.tgz#5c51a2e58dff7525b65f169721767173bf832694" @@ -13072,38 +11674,6 @@ jsdom@11.12.0: ws "^5.2.0" xml-name-validator "^3.0.0" -jsdom@^15.1.1: - version "15.2.1" - resolved "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz#d2feb1aef7183f86be521b8c6833ff5296d07ec5" - integrity sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g== - dependencies: - abab "^2.0.0" - acorn "^7.1.0" - acorn-globals "^4.3.2" - array-equal "^1.0.0" - cssom "^0.4.1" - cssstyle "^2.0.0" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.1" - html-encoding-sniffer "^1.0.2" - nwsapi "^2.2.0" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.7" - saxes "^3.1.9" - symbol-tree "^3.2.2" - tough-cookie "^3.0.1" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^7.0.0" - xml-name-validator "^3.0.0" - jsdom@^16.2.2: version "16.2.2" resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz#76f2f7541646beb46a938f5dc476b88705bedf2b" @@ -13393,13 +11963,6 @@ kuler@1.0.x: dependencies: colornames "^1.1.1" -latest-version@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" - integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU= - dependencies: - package-json "^4.0.0" - latest-version@^5.0.0: version "5.1.0" resolved "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" @@ -13422,11 +11985,6 @@ lazy-cache@^1.0.3: resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= -lazy-property@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz#84ddc4b370679ba8bd4cdcfa4c06b43d57111147" - integrity sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc= - lazy-universal-dotenv@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz#a6c8938414bca426ab8c9463940da451a911db38" @@ -13438,20 +11996,6 @@ lazy-universal-dotenv@^3.0.1: dotenv "^8.0.0" dotenv-expand "^5.1.0" -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - left-pad@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" @@ -13493,7 +12037,15 @@ levenary@^1.1.1: dependencies: leven "^3.1.0" -levn@^0.3.0, levn@~0.3.0: +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= @@ -13501,140 +12053,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libcipm@^4.0.7: - version "4.0.7" - resolved "https://registry.npmjs.org/libcipm/-/libcipm-4.0.7.tgz#76cd675c98bdaae64db88b782b01b804b6d02c8a" - integrity sha512-fTq33otU3PNXxxCTCYCYe7V96o59v/o7bvtspmbORXpgFk+wcWrGf5x6tBgui5gCed/45/wtPomBsZBYm5KbIw== - dependencies: - bin-links "^1.1.2" - bluebird "^3.5.1" - figgy-pudding "^3.5.1" - find-npm-prefix "^1.0.2" - graceful-fs "^4.1.11" - ini "^1.3.5" - lock-verify "^2.0.2" - mkdirp "^0.5.1" - npm-lifecycle "^3.0.0" - npm-logical-tree "^1.2.1" - npm-package-arg "^6.1.0" - pacote "^9.1.0" - read-package-json "^2.0.13" - rimraf "^2.6.2" - worker-farm "^1.6.0" - -libnpm@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/libnpm/-/libnpm-3.0.1.tgz#0be11b4c9dd4d1ffd7d95c786e92e55d65be77a2" - integrity sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ== - dependencies: - bin-links "^1.1.2" - bluebird "^3.5.3" - find-npm-prefix "^1.0.2" - libnpmaccess "^3.0.2" - libnpmconfig "^1.2.1" - libnpmhook "^5.0.3" - libnpmorg "^1.0.1" - libnpmpublish "^1.1.2" - libnpmsearch "^2.0.2" - libnpmteam "^1.0.2" - lock-verify "^2.0.2" - npm-lifecycle "^3.0.0" - npm-logical-tree "^1.2.1" - npm-package-arg "^6.1.0" - npm-profile "^4.0.2" - npm-registry-fetch "^4.0.0" - npmlog "^4.1.2" - pacote "^9.5.3" - read-package-json "^2.0.13" - stringify-package "^1.0.0" - -libnpmaccess@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz#8b2d72345ba3bef90d3b4f694edd5c0417f58923" - integrity sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ== - dependencies: - aproba "^2.0.0" - get-stream "^4.0.0" - npm-package-arg "^6.1.0" - npm-registry-fetch "^4.0.0" - -libnpmconfig@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz#c0c2f793a74e67d4825e5039e7a02a0044dfcbc0" - integrity sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA== - dependencies: - figgy-pudding "^3.5.1" - find-up "^3.0.0" - ini "^1.3.5" - -libnpmhook@^5.0.3: - version "5.0.3" - resolved "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.3.tgz#4020c0f5edbf08ebe395325caa5ea01885b928f7" - integrity sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA== - dependencies: - aproba "^2.0.0" - figgy-pudding "^3.4.1" - get-stream "^4.0.0" - npm-registry-fetch "^4.0.0" - -libnpmorg@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.1.tgz#5d2503f6ceb57f33dbdcc718e6698fea6d5ad087" - integrity sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww== - dependencies: - aproba "^2.0.0" - figgy-pudding "^3.4.1" - get-stream "^4.0.0" - npm-registry-fetch "^4.0.0" - -libnpmpublish@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.3.tgz#e3782796722d79eef1a0a22944c117e0c4ca4280" - integrity sha512-/3LsYqVc52cHXBmu26+J8Ed7sLs/hgGVFMH1mwYpL7Qaynb9RenpKqIKu0sJ130FB9PMkpMlWjlbtU8A4m7CQw== - dependencies: - aproba "^2.0.0" - figgy-pudding "^3.5.1" - get-stream "^4.0.0" - lodash.clonedeep "^4.5.0" - normalize-package-data "^2.4.0" - npm-package-arg "^6.1.0" - npm-registry-fetch "^4.0.0" - semver "^5.5.1" - ssri "^6.0.1" - -libnpmsearch@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.2.tgz#9a4f059102d38e3dd44085bdbfe5095f2a5044cf" - integrity sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg== - dependencies: - figgy-pudding "^3.5.1" - get-stream "^4.0.0" - npm-registry-fetch "^4.0.0" - -libnpmteam@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.2.tgz#8b48bcbb6ce70dd8150c950fcbdbf3feb6eec820" - integrity sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA== - dependencies: - aproba "^2.0.0" - figgy-pudding "^3.4.1" - get-stream "^4.0.0" - npm-registry-fetch "^4.0.0" - -libnpx@^10.2.2: - version "10.2.2" - resolved "https://registry.npmjs.org/libnpx/-/libnpx-10.2.2.tgz#5a4171b9b92dd031463ef66a4af9f5cbd6b09572" - integrity sha512-ujaYToga1SAX5r7FU5ShMFi88CWpY75meNZtr6RtEyv4l2ZK3+Wgvxq2IqlwWBiDZOqhumdeiocPS1aKrCMe3A== - dependencies: - dotenv "^5.0.1" - npm-package-arg "^6.0.0" - rimraf "^2.6.2" - safe-buffer "^5.1.0" - update-notifier "^2.3.0" - which "^1.3.0" - y18n "^4.0.0" - yargs "^11.0.0" - liftoff@3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" @@ -13661,25 +12079,6 @@ linkify-it@^2.0.0: dependencies: uc.micro "^1.0.1" -lint-staged@^10.0.4: - version "10.0.8" - resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-10.0.8.tgz#0f7849cdc336061f25f5d4fcbcfa385701ff4739" - integrity sha512-Oa9eS4DJqvQMVdywXfEor6F4vP+21fPHF8LUXgBbVWUSWBddjqsvO6Bv1LwMChmgQZZqwUvgJSHlu8HFHAPZmA== - dependencies: - chalk "^3.0.0" - commander "^4.0.1" - cosmiconfig "^6.0.0" - debug "^4.1.1" - dedent "^0.7.0" - execa "^3.4.0" - listr "^0.14.3" - log-symbols "^3.0.0" - micromatch "^4.0.2" - normalize-path "^3.0.0" - please-upgrade-node "^3.2.0" - string-argv "0.3.1" - stringify-object "^3.3.0" - lint-staged@^10.1.0: version "10.1.0" resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-10.1.0.tgz#18785bb005d5ed404f1c1db6563e082f7a7baac2" @@ -13840,61 +12239,22 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -lock-verify@^2.0.2, lock-verify@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/lock-verify/-/lock-verify-2.2.0.tgz#12432feb68bb647071c78c44bde16029a0f7d935" - integrity sha512-BhM1Vqsu7x0s+EalTifNjdDPks+ZjdAhComvnA6VcCIlDOI5ouELXqAe1BYuEIP4zGN0W08xVm6byJV1LnCiJg== - dependencies: - "@iarna/cli" "^1.2.0" - npm-package-arg "^6.1.0" - semver "^5.4.1" - -lockfile@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" - integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== - dependencies: - signal-exit "^3.0.2" - lodash-es@^4.17.11: version "4.17.15" resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== -lodash._baseuniq@~4.6.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" - integrity sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg= - dependencies: - lodash._createset "~4.0.0" - lodash._root "~3.0.0" - -lodash._createset@~4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" - integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= - lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= -lodash._root@~3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= - lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.capitalize@^4.2.1: - version "4.2.1" - resolved "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" - integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk= - -lodash.clonedeep@^4.5.0, lodash.clonedeep@~4.5.0: +lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= @@ -13904,11 +12264,6 @@ lodash.debounce@^4.0.8: resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash.escaperegexp@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" - integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c= - lodash.flattendeep@^4.0.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" @@ -13924,21 +12279,6 @@ lodash.ismatch@^4.4.0: resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= - -lodash.map@^4.5.1: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" - integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= - lodash.memoize@4.x, lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -13979,31 +12319,11 @@ lodash.throttle@^4.1.1: resolved "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= -lodash.toarray@^4.4.0: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" - integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE= - -lodash.union@~4.6.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" - integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= - -lodash.uniq@^4.5.0, lodash.uniq@~4.5.0: +lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash.uniqby@^4.7.0: - version "4.7.0" - resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" - integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= - -lodash.without@~4.4.0: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" - integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= - lodash@4.17.15, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.1: version "4.17.15" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" @@ -14048,18 +12368,6 @@ loglevel@^1.6.8: resolved "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== -lolex@^5.0.0: - version "5.1.2" - resolved "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" - integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== - dependencies: - "@sinonjs/commons" "^1.7.0" - -longest@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz#781e183296aa94f6d4d916dc335d0d17aefa23f8" - integrity sha1-eB4YMpaqlPbU2RbcM10NF676I/g= - loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -14193,13 +12501,6 @@ makeerror@1.0.x: dependencies: tmpl "1.0.x" -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.npmjs.org/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.0, map-cache@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -14256,23 +12557,6 @@ markdown-to-jsx@^6.9.1, markdown-to-jsx@^6.9.3: prop-types "^15.6.2" unquote "^1.1.0" -marked-terminal@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.0.0.tgz#2c7aa2c0eec496f05cd61f768d80d35db0bf6a86" - integrity sha512-mzU3VD7aVz12FfGoKFAceijehA6Ocjfg3rVimvJbFAB/NOYCsuzRVtq3PSFdPmWI5mhdGeEh3/aMJ5DSxAz94Q== - dependencies: - ansi-escapes "^4.3.0" - cardinal "^2.1.1" - chalk "^3.0.0" - cli-table "^0.3.1" - node-emoji "^1.10.0" - supports-hyperlinks "^2.0.0" - -marked@^0.8.0: - version "0.8.1" - resolved "https://registry.npmjs.org/marked/-/marked-0.8.1.tgz#a233f39572fab15ede53a3c3be8a139bff86d2dd" - integrity sha512-tZfJS8uE0zpo7xpTffwFwYRfW9AzNcdo04Qcjs+C9+oCy8MSRD2reD5iDVtYx8mtLaqsGughw/YLlcwNxAHA1g== - material-table@^1.58.0: version "1.58.2" resolved "https://registry.npmjs.org/material-table/-/material-table-1.58.2.tgz#dc0d19652848e6bb92f747d122bd7d4681cca6dc" @@ -14320,32 +12604,11 @@ mdurl@^1.0.1: resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= -meant@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d" - integrity sha512-UakVLFjKkbbUwNWJ2frVLnnAtbb7D7DsloxRd3s/gDpI8rdv8W5Hp3NaDb+POBI1fQdeussER6NB8vpcRURvlg== - media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.npmjs.org/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" - memoize-one@^5.0.4: version "5.1.1" resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" @@ -14374,21 +12637,6 @@ memory-fs@^0.5.0: errno "^0.1.3" readable-stream "^2.0.1" -meow@5.0.0, meow@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" - integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - yargs-parser "^10.0.0" - meow@^3.3.0: version "3.7.0" resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" @@ -14420,6 +12668,21 @@ meow@^4.0.0: redent "^2.0.0" trim-newlines "^2.0.0" +meow@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" + integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== + dependencies: + camelcase-keys "^4.0.0" + decamelize-keys "^1.0.0" + loud-rejection "^1.0.0" + minimist-options "^3.0.1" + normalize-package-data "^2.3.4" + read-pkg-up "^3.0.0" + redent "^2.0.0" + trim-newlines "^2.0.0" + yargs-parser "^10.0.0" + merge-deep@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2" @@ -14444,11 +12707,6 @@ merge2@^1.2.3, merge2@^1.3.0: resolved "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== -merge@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" - integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== - methods@^1.0.0, methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -14528,7 +12786,7 @@ mime@1.6.0, mime@^1.4.1: resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.3.1, mime@^2.4.3, mime@^2.4.4: +mime@^2.3.1, mime@^2.4.4: version "2.4.4" resolved "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== @@ -14538,7 +12796,7 @@ mimic-fn@^1.0.0: resolved "https://registry.npmjs.org/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.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== @@ -14613,11 +12871,6 @@ minimist-options@^3.0.1: arrify "^1.0.1" is-plain-obj "^1.1.0" -minimist@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - minimist@1.2.5, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" @@ -14728,7 +12981,7 @@ mkdirp@*, mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@0.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -14904,11 +13157,6 @@ neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== -nerf-dart@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz#e6dab7febf5ad816ea81cf5c629c5a0ebde72c1a" - integrity sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo= - nice-try@^1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -14939,13 +13187,6 @@ node-dir@^0.1.10: dependencies: minimatch "^3.0.2" -node-emoji@^1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" - integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw== - dependencies: - lodash.toarray "^4.4.0" - node-fetch-npm@^2.0.2: version "2.0.3" resolved "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.3.tgz#efae4aacb0500444e449a51fc1467397775ebc38" @@ -14965,7 +13206,7 @@ node-forge@0.9.0: resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== -node-gyp@^5.0.2, node-gyp@^5.1.0: +node-gyp@^5.0.2: version "5.1.0" resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz#8e31260a7af4a2e2f994b0673d4e0b3866156332" integrity sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw== @@ -15021,17 +13262,6 @@ node-modules-regexp@^1.0.0: resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-notifier@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-6.0.0.tgz#cea319e06baa16deec8ce5cd7f133c4a46b68e12" - integrity sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw== - dependencies: - growly "^1.3.0" - is-wsl "^2.1.1" - semver "^6.3.0" - shellwords "^0.1.1" - which "^1.3.1" - node-notifier@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-7.0.0.tgz#513bc42f2aa3a49fce1980a7ff375957c71f718a" @@ -15083,7 +13313,7 @@ nodemon@^2.0.2: undefsafe "^2.0.2" update-notifier "^4.0.0" -nopt@^4.0.1, nopt@~4.0.1: +nopt@^4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== @@ -15145,19 +13375,6 @@ normalize-url@^4.1.0: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== -normalize-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-5.0.0.tgz#f46c9dc20670495e4e18fbd1b4396e41d199f63c" - integrity sha512-bAEm2fx8Dq/a35Z6PIRkkBBJvR56BbEJvhpNtvCZ4W9FyORSna77fn+xtYFjqk5JpBS+fMnAOG/wFgkQBmB7hw== - -npm-audit-report@^1.3.2: - version "1.3.2" - resolved "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.2.tgz#303bc78cd9e4c226415076a4f7e528c89fc77018" - integrity sha512-abeqS5ONyXNaZJPGAf6TOUMNdSe1Y6cpc9MLBRn+CuUoYbfdca6AxOyXVlfIv9OgKX+cacblbG5w7A6ccwoTPw== - dependencies: - cli-table3 "^0.5.0" - console-control-strings "^1.1.0" - npm-bundled@^1.0.1: version "1.1.1" resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" @@ -15165,19 +13382,7 @@ npm-bundled@^1.0.1: dependencies: npm-normalize-package-bin "^1.0.1" -npm-cache-filename@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" - integrity sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE= - -npm-install-checks@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.2.tgz#ab2e32ad27baa46720706908e5b14c1852de44d9" - integrity sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg== - dependencies: - semver "^2.3.0 || 3.x || 4 || 5" - -npm-lifecycle@^3.0.0, npm-lifecycle@^3.1.2, npm-lifecycle@^3.1.4: +npm-lifecycle@^3.1.2: version "3.1.4" resolved "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.4.tgz#de6975c7d8df65f5150db110b57cce498b0b604c" integrity sha512-tgs1PaucZwkxECGKhC/stbEgFyc3TGh2TJcg2CDr6jbvQRdteHNhmMeljRzpe4wgFAXQADoy1cSqqi7mtiAa5A== @@ -15191,17 +13396,12 @@ npm-lifecycle@^3.0.0, npm-lifecycle@^3.1.2, npm-lifecycle@^3.1.4: umask "^1.1.0" which "^1.3.1" -npm-logical-tree@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz#44610141ca24664cad35d1e607176193fd8f5b88" - integrity sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg== - npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0, npm-package-arg@^6.1.1: +"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: version "6.1.1" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz#02168cb0a49a2b75bf988a28698de7b529df5cb7" integrity sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== @@ -15211,7 +13411,7 @@ npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: semver "^5.6.0" validate-npm-package-name "^3.0.0" -npm-packlist@^1.1.12, npm-packlist@^1.1.6, npm-packlist@^1.4.4, npm-packlist@^1.4.8: +npm-packlist@^1.1.6, npm-packlist@^1.4.4: version "1.4.8" resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== @@ -15220,7 +13420,7 @@ npm-packlist@^1.1.12, npm-packlist@^1.1.6, npm-packlist@^1.4.4, npm-packlist@^1. npm-bundled "^1.0.1" npm-normalize-package-bin "^1.0.1" -npm-pick-manifest@^3.0.0, npm-pick-manifest@^3.0.2: +npm-pick-manifest@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz#f4d9e5fd4be2153e5f4e5f9b7be8dc419a99abb7" integrity sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw== @@ -15229,28 +13429,6 @@ npm-pick-manifest@^3.0.0, npm-pick-manifest@^3.0.2: npm-package-arg "^6.0.0" semver "^5.4.1" -npm-profile@^4.0.2, npm-profile@^4.0.4: - version "4.0.4" - resolved "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz#28ee94390e936df6d084263ee2061336a6a1581b" - integrity sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ== - dependencies: - aproba "^1.1.2 || 2" - figgy-pudding "^3.4.1" - npm-registry-fetch "^4.0.0" - -npm-registry-fetch@^4.0.0, npm-registry-fetch@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz#3c2179e39e04f9348b1c2979545951d36bee8766" - integrity sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw== - dependencies: - JSONStream "^1.3.4" - bluebird "^3.5.1" - figgy-pudding "^3.4.1" - lru-cache "^5.1.1" - make-fetch-happen "^5.0.0" - npm-package-arg "^6.1.0" - safe-buffer "^5.2.0" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -15265,133 +13443,7 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -npm-user-validate@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.0.tgz#8ceca0f5cea04d4e93519ef72d0557a75122e951" - integrity sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE= - -npm@^6.10.3: - version "6.14.3" - resolved "https://registry.npmjs.org/npm/-/npm-6.14.3.tgz#a122618543c6670765cf5e827cd996b5552f9b65" - integrity sha512-3tQYVEEdSGQGYoXhZvNqW8faqCidfMMaL387RdDo4Uu5kQy4IgvJ13NIsWVMQ6e3QWlbicNMSpFiyzYfMUuPDw== - dependencies: - JSONStream "^1.3.5" - abbrev "~1.1.1" - ansicolors "~0.3.2" - ansistyles "~0.1.3" - aproba "^2.0.0" - archy "~1.0.0" - bin-links "^1.1.7" - bluebird "^3.5.5" - byte-size "^5.0.1" - cacache "^12.0.3" - call-limit "^1.1.1" - chownr "^1.1.4" - ci-info "^2.0.0" - cli-columns "^3.1.2" - cli-table3 "^0.5.1" - cmd-shim "^3.0.3" - columnify "~1.5.4" - config-chain "^1.1.12" - detect-indent "~5.0.0" - detect-newline "^2.1.0" - dezalgo "~1.0.3" - editor "~1.0.0" - figgy-pudding "^3.5.1" - find-npm-prefix "^1.0.2" - fs-vacuum "~1.2.10" - fs-write-stream-atomic "~1.0.10" - gentle-fs "^2.3.0" - glob "^7.1.6" - graceful-fs "^4.2.3" - has-unicode "~2.0.1" - hosted-git-info "^2.8.8" - iferr "^1.0.2" - infer-owner "^1.0.4" - inflight "~1.0.6" - inherits "^2.0.4" - ini "^1.3.5" - init-package-json "^1.10.3" - is-cidr "^3.0.0" - json-parse-better-errors "^1.0.2" - lazy-property "~1.0.0" - libcipm "^4.0.7" - libnpm "^3.0.1" - libnpmaccess "^3.0.2" - libnpmhook "^5.0.3" - libnpmorg "^1.0.1" - libnpmsearch "^2.0.2" - libnpmteam "^1.0.2" - libnpx "^10.2.2" - lock-verify "^2.1.0" - lockfile "^1.0.4" - lodash._baseuniq "~4.6.0" - lodash.clonedeep "~4.5.0" - lodash.union "~4.6.0" - lodash.uniq "~4.5.0" - lodash.without "~4.4.0" - lru-cache "^5.1.1" - meant "~1.0.1" - mississippi "^3.0.0" - mkdirp "^0.5.3" - move-concurrently "^1.0.1" - node-gyp "^5.1.0" - nopt "~4.0.1" - normalize-package-data "^2.5.0" - npm-audit-report "^1.3.2" - npm-cache-filename "~1.0.2" - npm-install-checks "^3.0.2" - npm-lifecycle "^3.1.4" - npm-package-arg "^6.1.1" - npm-packlist "^1.4.8" - npm-pick-manifest "^3.0.2" - npm-profile "^4.0.4" - npm-registry-fetch "^4.0.3" - npm-user-validate "~1.0.0" - npmlog "~4.1.2" - once "~1.4.0" - opener "^1.5.1" - osenv "^0.1.5" - pacote "^9.5.12" - path-is-inside "~1.0.2" - promise-inflight "~1.0.1" - qrcode-terminal "^0.12.0" - query-string "^6.8.2" - qw "~1.0.1" - read "~1.0.7" - read-cmd-shim "^1.0.5" - read-installed "~4.0.3" - read-package-json "^2.1.1" - read-package-tree "^5.3.1" - readable-stream "^3.6.0" - readdir-scoped-modules "^1.1.0" - request "^2.88.0" - retry "^0.12.0" - rimraf "^2.7.1" - safe-buffer "^5.1.2" - semver "^5.7.1" - sha "^3.0.0" - slide "~1.1.6" - sorted-object "~2.0.1" - sorted-union-stream "~2.1.3" - ssri "^6.0.1" - stringify-package "^1.0.1" - tar "^4.4.13" - text-table "~0.2.0" - tiny-relative-date "^1.3.0" - uid-number "0.0.6" - umask "~1.1.0" - unique-filename "^1.1.1" - unpipe "~1.0.0" - update-notifier "^2.5.0" - uuid "^3.3.3" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "~3.0.0" - which "^1.3.1" - worker-farm "^1.7.0" - write-file-atomic "^2.4.3" - -npmlog@^4.0.2, npmlog@^4.1.2, npmlog@~4.1.2: +npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -15564,7 +13616,7 @@ on-headers@~1.0.2: resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0, once@^1.3.1, once@^1.4.0, once@~1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -15615,11 +13667,6 @@ opencollective-postinstall@^2.0.2: resolved "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== -opener@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" - integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== - opn@^5.5.0: version "5.5.0" resolved "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" @@ -15627,7 +13674,7 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" -optionator@^0.8.1, optionator@^0.8.3: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -15639,6 +13686,18 @@ optionator@^0.8.1, optionator@^0.8.3: type-check "~0.3.2" word-wrap "~1.2.3" +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + ora@*, ora@^4.0.3: version "4.0.4" resolved "https://registry.npmjs.org/ora/-/ora-4.0.4.tgz#e8da697cc5b6a47266655bf68e0fb588d29a545d" @@ -15670,24 +13729,6 @@ os-homedir@^1.0.0: resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - -os-locale@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/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-name@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" @@ -15719,23 +13760,11 @@ p-cancelable@^1.0.0: resolved "https://registry.npmjs.org/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.npmjs.org/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - p-each-series@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== -p-filter@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz#1b1472562ae7a0f742f0f3d3d3718ea66ff9c09c" - integrity sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw== - dependencies: - p-map "^2.0.0" - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -15746,16 +13775,6 @@ p-finally@^2.0.0: resolved "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== - -p-is-promise@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz#58e78c7dfe2e163cf2a04ff869e7c1dba64a5971" - integrity sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ== - p-limit@2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -15842,11 +13861,6 @@ p-reduce@^1.0.0: resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= -p-reduce@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" - integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== - p-retry@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" @@ -15854,14 +13868,6 @@ p-retry@^3.0.1: dependencies: retry "^0.12.0" -p-retry@^4.0.0: - version "4.2.0" - resolved "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz#ea9066c6b44f23cab4cd42f6147cdbbc6604da5d" - integrity sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA== - dependencies: - "@types/retry" "^0.12.0" - retry "^0.12.0" - p-timeout@^3.1.0: version "3.2.0" resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" @@ -15886,16 +13892,6 @@ p-waterfall@^1.0.0: dependencies: p-reduce "^1.0.0" -package-json@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" - integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0= - dependencies: - got "^6.7.1" - registry-auth-token "^3.0.1" - registry-url "^3.0.3" - semver "^5.1.0" - package-json@^6.3.0: version "6.5.0" resolved "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -15906,42 +13902,6 @@ package-json@^6.3.0: registry-url "^5.0.0" semver "^6.2.0" -pacote@^9.1.0, pacote@^9.5.12, pacote@^9.5.3: - version "9.5.12" - resolved "https://registry.npmjs.org/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" - infer-owner "^1.0.4" - lru-cache "^5.1.1" - make-fetch-happen "^5.0.0" - minimatch "^3.0.4" - minipass "^2.3.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 "^3.0.0" - npm-registry-fetch "^4.0.0" - osenv "^0.1.5" - promise-inflight "^1.0.1" - promise-retry "^1.1.1" - protoduck "^5.0.1" - rimraf "^2.6.2" - safe-buffer "^5.1.2" - semver "^5.6.0" - ssri "^6.0.1" - tar "^4.4.10" - unique-filename "^1.1.1" - which "^1.3.1" - pako@~1.0.5: version "1.0.11" resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -16067,11 +14027,6 @@ parse5@4.0.0: resolved "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== -parse5@5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" - integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== - parse5@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" @@ -16158,7 +14113,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= @@ -16312,14 +14267,6 @@ pirates@^4.0.1: dependencies: node-modules-regexp "^1.0.0" -pkg-conf@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" - integrity sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg= - dependencies: - find-up "^2.0.0" - load-json-file "^4.0.0" - pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" @@ -16807,12 +14754,17 @@ postcss@^6.0.1: source-map "^0.6.1" supports-color "^5.4.0" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prepend-http@^1.0.0, prepend-http@^1.0.1: +prepend-http@^1.0.0: version "1.0.4" resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= @@ -16822,7 +14774,7 @@ prepend-http@^2.0.0: resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@^1.16.4, prettier@^1.18.2: +prettier@^1.16.4: version "1.19.1" resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== @@ -16845,7 +14797,7 @@ pretty-error@^2.1.1: renderkid "^2.0.1" utila "~0.4" -pretty-format@^24.3.0, pretty-format@^24.9.0: +pretty-format@^24.3.0: version "24.9.0" resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== @@ -16914,7 +14866,7 @@ progress@^2.0.0: resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -promise-inflight@^1.0.1, promise-inflight@~1.0.1: +promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= @@ -17109,11 +15061,6 @@ q@^1.1.2, q@^1.5.1: resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -qrcode-terminal@^0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" - integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ== - qs@6.7.0: version "6.7.0" resolved "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -17137,15 +15084,6 @@ query-string@^4.1.0: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.8.2: - version "6.11.1" - resolved "https://registry.npmjs.org/query-string/-/query-string-6.11.1.tgz#ab021f275d463ce1b61e88f0ce6988b3e8fe7c2c" - integrity sha512-1ZvJOUl8ifkkBxu2ByVM/8GijMIPx+cef7u3yroO3Ogm4DOdZcF5dcrWTIlSHe3Pg/mtlt6/eFjObDfJureZZA== - dependencies: - decode-uri-component "^0.2.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" - querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -17166,11 +15104,6 @@ quick-lru@^1.0.0: resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= -qw@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4" - integrity sha1-77/cdA+a0FQwRCassYNBLMi5ltQ= - raf-schd@^4.0.0: version "4.0.2" resolved "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.2.tgz#bd44c708188f2e84c810bf55fcea9231bcaed8a0" @@ -17239,7 +15172,7 @@ rc-progress@^3.0.0: dependencies: classnames "^2.2.6" -rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: +rc@^1.2.7, rc@^1.2.8: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -17655,28 +15588,14 @@ react@^16.0.0, react@^16.12.0, react@^16.13.1, react@^16.8.3: object-assign "^4.1.1" prop-types "^15.6.2" -read-cmd-shim@^1.0.1, read-cmd-shim@^1.0.5: +read-cmd-shim@^1.0.1: version "1.0.5" resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz#87e43eba50098ba5a32d0ceb583ab8e43b961c16" integrity sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA== dependencies: graceful-fs "^4.1.2" -read-installed@~4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" - integrity sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc= - dependencies: - debuglog "^1.0.1" - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - semver "2 || 3 || 4 || 5" - slide "~1.1.3" - util-extend "^1.0.1" - optionalDependencies: - graceful-fs "^4.1.2" - -"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13, read-package-json@^2.1.1: +"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13: version "2.1.1" resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz#16aa66c59e7d4dad6288f179dd9295fd59bb98f1" integrity sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A== @@ -17688,7 +15607,7 @@ read-installed@~4.0.3: optionalDependencies: graceful-fs "^4.1.2" -read-package-tree@^5.1.6, read-package-tree@^5.3.1: +read-package-tree@^5.1.6: version "5.3.1" resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== @@ -17721,7 +15640,7 @@ read-pkg-up@^3.0.0: find-up "^2.0.0" read-pkg "^3.0.0" -read-pkg-up@^7.0.0, read-pkg-up@^7.0.1: +read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== @@ -17757,7 +15676,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -read-pkg@^5.0.0, read-pkg@^5.2.0: +read-pkg@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== @@ -17767,7 +15686,7 @@ read-pkg@^5.0.0, read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -read@1, read@~1.0.1, read@~1.0.7: +read@1, read@~1.0.1: version "1.0.7" resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= @@ -17787,7 +15706,7 @@ read@1, read@~1.0.1, read@~1.0.7: string_decoder "~1.1.1" util-deprecate "~1.0.1" -"readable-stream@2 || 3", readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: +"readable-stream@2 || 3", readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0: version "3.6.0" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -17796,17 +15715,7 @@ read@1, read@~1.0.1, read@~1.0.7: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@~1.1.10: - version "1.1.14" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readdir-scoped-modules@^1.0.0, readdir-scoped-modules@^1.1.0: +readdir-scoped-modules@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== @@ -17832,13 +15741,6 @@ readdirp@~3.4.0: dependencies: picomatch "^2.2.1" -realpath-native@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" - integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== - dependencies: - util.promisify "^1.0.0" - recast@^0.14.7: version "0.14.7" resolved "https://registry.npmjs.org/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d" @@ -17887,13 +15789,6 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -redeyed@~2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" - integrity sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs= - dependencies: - esprima "~4.0.0" - redux@^4.0.1: version "4.0.5" resolved "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" @@ -17928,11 +15823,6 @@ regenerate@^1.4.0: resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== -regenerator-runtime@^0.10.5: - version "0.10.5" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" - integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= - regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -17967,16 +15857,16 @@ regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - regexpp@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== +regexpp@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + regexpu-core@^4.6.0, regexpu-core@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" @@ -17989,14 +15879,6 @@ regexpu-core@^4.6.0, regexpu-core@^4.7.0: 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.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" - integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A== - dependencies: - rc "^1.1.6" - safe-buffer "^5.0.1" - registry-auth-token@^4.0.0: version "4.1.1" resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz#40a33be1e82539460f94328b0f7f0f84c16d9479" @@ -18004,13 +15886,6 @@ registry-auth-token@^4.0.0: dependencies: rc "^1.2.8" -registry-url@^3.0.3: - version "3.1.0" - resolved "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= - dependencies: - rc "^1.0.1" - registry-url@^5.0.0: version "5.1.0" resolved "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" @@ -18117,7 +15992,7 @@ request-promise-core@1.1.3: dependencies: lodash "^4.17.15" -request-promise-native@^1.0.5, request-promise-native@^1.0.7, request-promise-native@^1.0.8: +request-promise-native@^1.0.5, request-promise-native@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== @@ -18157,11 +16032,6 @@ require-directory@^2.1.1: resolved "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -18214,13 +16084,6 @@ resolve-from@^4.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve-global@1.0.0, resolve-global@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" - integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== - dependencies: - global-dirs "^0.1.1" - resolve-pathname@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" @@ -18231,11 +16094,6 @@ resolve-url@^0.2.1: resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - resolve@1.15.1: version "1.15.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" @@ -18243,7 +16101,7 @@ resolve@1.15.1: dependencies: path-parse "^1.0.6" -resolve@1.x, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.16.1, resolve@^1.17.0, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.16.1, resolve@^1.17.0, resolve@^1.3.2: version "1.17.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== @@ -18318,11 +16176,6 @@ rifm@^0.7.0: dependencies: "@babel/runtime" "^7.3.1" -right-pad@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz#8ca08c2cbb5b55e74dafa96bf7fd1a27d568c8d0" - integrity sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA= - rimraf@2.6.3: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -18330,7 +16183,7 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: +rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -18546,13 +16399,6 @@ sax@^1.2.4, sax@~1.2.4: resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -saxes@^3.1.9: - version "3.1.11" - resolved "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" - integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== - dependencies: - xmlchars "^2.1.1" - saxes@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" @@ -18607,52 +16453,11 @@ selfsigned@^1.10.7: dependencies: node-forge "0.9.0" -semantic-release@^17.0.1: - version "17.0.4" - resolved "https://registry.npmjs.org/semantic-release/-/semantic-release-17.0.4.tgz#4ca739b2bf80f8ce5e49b05f12c15f49ca233d6d" - integrity sha512-5y9QRSrZtdvACmlpX5DvEVsvFuKRDUVn7JVJFxPVLGrGofDf1d0M/+hA1wFmCjiJZ+VCY8bYaSqVqF14KCF9rw== - dependencies: - "@semantic-release/commit-analyzer" "^8.0.0" - "@semantic-release/error" "^2.2.0" - "@semantic-release/github" "^7.0.0" - "@semantic-release/npm" "^7.0.0" - "@semantic-release/release-notes-generator" "^9.0.0" - aggregate-error "^3.0.0" - cosmiconfig "^6.0.0" - debug "^4.0.0" - env-ci "^5.0.0" - execa "^4.0.0" - figures "^3.0.0" - find-versions "^3.0.0" - get-stream "^5.0.0" - git-log-parser "^1.2.0" - hook-std "^2.0.0" - hosted-git-info "^3.0.0" - lodash "^4.17.15" - marked "^0.8.0" - marked-terminal "^4.0.0" - micromatch "^4.0.2" - p-each-series "^2.1.0" - p-reduce "^2.0.0" - read-pkg-up "^7.0.0" - resolve-from "^5.0.0" - semver "^7.1.1" - semver-diff "^3.1.1" - signale "^1.2.1" - yargs "^15.0.1" - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/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.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" - integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= - dependencies: - semver "^5.0.3" - semver-diff@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" @@ -18665,26 +16470,26 @@ semver-regex@^2.0.0: resolved "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@6.3.0, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - semver@7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@7.x, semver@^7.1.1, semver@^7.1.2, semver@^7.2.1, semver@^7.3.2: +semver@7.x, semver@^7.2.1, semver@^7.3.2: version "7.3.2" resolved "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + send@0.17.1: version "0.17.1" resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -18786,13 +16591,6 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -sha@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/sha/-/sha-3.0.0.tgz#b2f2f90af690c16a3a839a6a6c680ea51fedd1ae" - integrity sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw== - dependencies: - graceful-fs "^4.1.2" - shallow-clone@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060" @@ -18849,15 +16647,6 @@ shell-quote@1.7.2: resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== -shelljs@0.7.6: - version "0.7.6" - resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad" - integrity sha1-N5zM+1a5HIYB5HkzVutTgpJN6a0= - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - shelljs@^0.8.3: version "0.8.3" resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" @@ -18885,15 +16674,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -signale@^1.2.1: - version "1.4.0" - resolved "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz#c4be58302fb0262ac00fc3d886a7c113759042f1" - integrity sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w== - dependencies: - chalk "^2.3.2" - figures "^2.0.0" - pkg-conf "^2.1.0" - simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -18955,7 +16735,7 @@ slice-ansi@^2.1.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -slide@^1.1.6, slide@~1.1.3, slide@~1.1.6: +slide@^1.1.6: version "1.1.6" resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= @@ -19046,19 +16826,6 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" -sorted-object@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" - integrity sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw= - -sorted-union-stream@~2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz#c7794c7e077880052ff71a8d4a2dbb4a9a638ac7" - integrity sha1-x3lMfgd4gAUv9xqNSi27Sppjisc= - dependencies: - from2 "^1.3.0" - stream-iterate "^1.1.0" - source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" @@ -19118,11 +16885,6 @@ space-separated-tokens@^1.0.0: resolved "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== -spawn-error-forwarder@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz#1afd94738e999b0346d7b9fc373be55e07577029" - integrity sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk= - spdx-correct@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" @@ -19177,11 +16939,6 @@ split-ca@^1.0.1: resolved "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" integrity sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY= -split-on-first@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" - integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== - split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -19196,13 +16953,6 @@ split2@^2.0.0: dependencies: through2 "^2.0.2" -split2@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz#52e2e221d88c75f9a73f90556e263ff96772b314" - integrity sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ= - dependencies: - through2 "~2.0.0" - split@0.3: version "0.3.3" resolved "https://registry.npmjs.org/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" @@ -19293,11 +17043,6 @@ stack-trace@0.0.x: resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= -stack-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" - integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== - stack-utils@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593" @@ -19384,14 +17129,6 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" -stream-combiner2@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" - integrity sha1-+02KFCDqNidk4hrUeAOXvry0HL4= - dependencies: - duplexer2 "~0.1.0" - readable-stream "^2.0.2" - stream-combiner@~0.0.4: version "0.0.4" resolved "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" @@ -19418,14 +17155,6 @@ stream-http@^2.7.2: to-arraybuffer "^1.0.0" xtend "^4.0.0" -stream-iterate@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz#2bd7c77296c1702a46488b8ad41f79865eecd4e1" - integrity sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE= - dependencies: - readable-stream "^2.1.5" - stream-shift "^1.0.0" - stream-shift@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" @@ -19441,11 +17170,6 @@ strict-uri-encode@^1.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= -strict-uri-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - string-argv@0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -19461,14 +17185,6 @@ string-hash@^1.1.1: resolved "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= -string-length@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" - integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== - dependencies: - astral-regex "^1.0.0" - strip-ansi "^5.2.0" - string-length@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" @@ -19486,7 +17202,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -19563,11 +17279,6 @@ string_decoder@^1.0.0, string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -19584,11 +17295,6 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -stringify-package@^1.0.0, stringify-package@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" - integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== - 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.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -19617,11 +17323,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-bom@4.0.0, strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -19634,6 +17335,11 @@ strip-bom@^3.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -19663,10 +17369,10 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@3.0.1, strip-json-comments@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" - integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== +strip-json-comments@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" + integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== strip-json-comments@~2.0.1: version "2.0.1" @@ -19896,7 +17602,7 @@ tar-stream@^2.0.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4, tar@^4.4.10, tar@^4.4.12, tar@^4.4.13, tar@^4.4.8: +tar@^4, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: version "4.4.13" resolved "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== @@ -19945,11 +17651,6 @@ temp-dir@^1.0.0: resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= -temp-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" - integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== - temp-write@^3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/temp-write/-/temp-write-3.4.0.tgz#8cff630fb7e9da05f047c74ce4ce4d685457d492" @@ -19962,23 +17663,6 @@ temp-write@^3.4.0: temp-dir "^1.0.0" uuid "^3.0.1" -tempy@^0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/tempy/-/tempy-0.5.0.tgz#2785c89df39fcc4d1714fc554813225e1581d70b" - integrity sha512-VEY96x7gbIRfsxqsafy2l5yVxxp3PhwAGoWMyC2D2Zt5DmEv+2tGiPOrquNRpf21hhGnKLVEsuqleqiZmKG/qw== - dependencies: - is-stream "^2.0.0" - temp-dir "^2.0.0" - type-fest "^0.12.0" - unique-string "^2.0.0" - -term-size@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" - integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= - dependencies: - execa "^0.7.0" - term-size@^2.1.0: version "2.2.0" resolved "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" @@ -20055,7 +17739,7 @@ text-hex@1.0.x: resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== -text-table@0.2.0, text-table@^0.2.0, text-table@~0.2.0: +text-table@0.2.0, text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= @@ -20101,7 +17785,7 @@ throttleit@^1.0.0: resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw= -through2@^2.0.0, through2@^2.0.2, through2@~2.0.0: +through2@^2.0.0, through2@^2.0.2: version "2.0.5" resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -20136,11 +17820,6 @@ timeago.js@^4.0.2: resolved "https://registry.npmjs.org/timeago.js/-/timeago.js-4.0.2.tgz#724e8c8833e3490676c7bb0a75f5daf20e558028" integrity sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w== -timed-out@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - timers-browserify@^2.0.4: version "2.0.11" resolved "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" @@ -20163,11 +17842,6 @@ tiny-invariant@^1.0.2, tiny-invariant@^1.0.4, tiny-invariant@^1.0.6: resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== -tiny-relative-date@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" - integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A== - tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" @@ -20292,11 +17966,6 @@ tr46@^2.0.2: dependencies: punycode "^2.1.1" -traverse@~0.6.6: - version "0.6.6" - resolved "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" - integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= - trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -20359,22 +18028,6 @@ ts-invariant@^0.4.0: dependencies: tslib "^1.9.3" -ts-jest@^25.2.1: - version "25.2.1" - resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-25.2.1.tgz#49bf05da26a8b7fbfbc36b4ae2fcdc2fef35c85d" - integrity sha512-TnntkEEjuXq/Gxpw7xToarmHbAafgCaAzOpnajnFC6jI7oo1trMzAHA04eWpc3MhV6+yvhE8uUBAmN+teRJh0A== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - json5 "2.x" - lodash.memoize "4.x" - make-error "1.x" - mkdirp "0.x" - resolve "1.x" - semver "^5.5" - yargs-parser "^16.1.0" - ts-jest@^26.0.0: version "26.0.0" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.0.0.tgz#957b802978249aaf74180b9dcb17b4fd787ad6f3" @@ -20473,6 +18126,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -20490,11 +18150,6 @@ type-fest@^0.11.0: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== -type-fest@^0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz#f57a27ab81c68d136a51fd71467eff94157fa1ee" - integrity sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg== - type-fest@^0.3.0: version "0.3.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" @@ -20535,7 +18190,7 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.7.4, typescript@^3.9.2: +typescript@^3.9.2, typescript@^3.9.3: version "3.9.3" resolved "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a" integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ== @@ -20563,7 +18218,7 @@ uid2@0.0.x: resolved "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I= -umask@^1.1.0, umask@~1.1.0: +umask@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= @@ -20662,13 +18317,6 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" -unique-string@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" - integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= - dependencies: - crypto-random-string "^1.0.0" - unique-string@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" @@ -20766,32 +18414,11 @@ untildify@4.0.0: resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== -unzip-response@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" - integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= - upath@^1.1.1, upath@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -update-notifier@^2.2.0, update-notifier@^2.3.0, update-notifier@^2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" - integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw== - dependencies: - boxen "^1.2.1" - chalk "^2.0.1" - configstore "^3.0.0" - import-lazy "^2.1.0" - is-ci "^1.0.10" - is-installed-globally "^0.1.0" - is-npm "^1.0.0" - latest-version "^3.0.0" - semver-diff "^2.0.0" - xdg-basedir "^3.0.0" - update-notifier@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz#4866b98c3bc5b5473c020b1250583628f9a328f3" @@ -20823,11 +18450,6 @@ urix@^0.1.0: resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-join@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" - integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== - url-loader@^2.0.1: version "2.3.0" resolved "https://registry.npmjs.org/url-loader/-/url-loader-2.3.0.tgz#e0e2ef658f003efb8ca41b0f3ffbf76bab88658b" @@ -20846,13 +18468,6 @@ url-loader@^4.1.0: mime-types "^2.1.26" schema-utils "^2.6.5" -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" @@ -20904,11 +18519,6 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util-extend@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" - integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8= - util-promisify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" @@ -20924,7 +18534,7 @@ util.promisify@1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" -util.promisify@^1.0.0, util.promisify@~1.0.0: +util.promisify@~1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== @@ -20958,7 +18568,7 @@ utils-merge@1.0.1, utils-merge@1.x.x: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.0.1, uuid@^3.3.2, uuid@^3.3.3, uuid@^3.4.0: +uuid@^3.0.1, uuid@^3.3.2, uuid@^3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -20978,15 +18588,6 @@ v8-compile-cache@^2.0.3: resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== -v8-to-istanbul@^4.0.1: - version "4.1.2" - resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.2.tgz#387d173be5383dbec209d21af033dcb892e3ac82" - integrity sha512-G9R+Hpw0ITAmPSr47lSlc5A1uekSYzXxTMlFxso2xoffwo4jQnzbv1p9yXIinO8UMZKfAFewaCHwWvnH4Jb4Ug== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - v8-to-istanbul@^4.1.3: version "4.1.4" resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" @@ -21008,7 +18609,7 @@ valid-url@1.0.9: resolved "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= -validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3, validate-npm-package-license@^3.0.4: +validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3: version "3.0.4" resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== @@ -21016,7 +18617,7 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3, valida spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: +validate-npm-package-name@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= @@ -21086,15 +18687,6 @@ w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2: dependencies: browser-process-hrtime "^1.0.0" -w3c-xmlserializer@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" - integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== - dependencies: - domexception "^1.0.1" - webidl-conversions "^4.0.2" - xml-name-validator "^3.0.0" - w3c-xmlserializer@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" @@ -21363,7 +18955,7 @@ which-pm-runs@^1.0.0: resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= -which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: +which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -21384,13 +18976,6 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -widest-line@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" - integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== - dependencies: - string-width "^2.1.1" - widest-line@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" @@ -21428,7 +19013,7 @@ winston@^3.2.1: triple-beam "^1.3.0" winston-transport "^4.3.0" -word-wrap@^1.0.3, word-wrap@~1.2.3: +word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== @@ -21438,7 +19023,7 @@ wordwrap@^1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -worker-farm@^1.6.0, worker-farm@^1.7.0: +worker-farm@^1.7.0: version "1.7.0" resolved "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== @@ -21452,14 +19037,6 @@ worker-rpc@^0.1.0: dependencies: microevent.ts "~0.1.1" -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" @@ -21491,7 +19068,7 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2, write-file-atomic@^2.4.3: +write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: version "2.4.3" resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== @@ -21563,7 +19140,7 @@ ws@^6.1.2, ws@^6.2.1: dependencies: async-limiter "~1.0.0" -ws@^7.0.0, ws@^7.2.3: +ws@^7.2.3: version "7.3.0" resolved "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== @@ -21578,11 +19155,6 @@ x-xss-protection@1.3.0: resolved "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz#3e3a8dd638da80421b0e9fff11a2dbe168f6d52c" integrity sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg== -xdg-basedir@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" - integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= - xdg-basedir@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" @@ -21593,12 +19165,7 @@ xml-name-validator@^3.0.0: resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xml@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" - integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= - -xmlchars@^2.1.1, xmlchars@^2.2.0: +xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== @@ -21615,11 +19182,6 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= - y18n@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" @@ -21685,14 +19247,6 @@ yargs-parser@^15.0.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^16.1.0: - version "16.1.0" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1" - integrity sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^18.1.1: version "18.1.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.1.tgz#bf7407b915427fc760fcbbccc6c82b4f0ffcbd37" @@ -21701,38 +19255,6 @@ yargs-parser@^18.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= - dependencies: - camelcase "^4.1.0" - -yargs-parser@^9.0.2: - version "9.0.2" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" - integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= - dependencies: - camelcase "^4.1.0" - -yargs@^11.0.0: - version "11.1.1" - resolved "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz#5052efe3446a4df5ed669c995886cc0f13702766" - integrity sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw== - dependencies: - cliui "^4.0.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^3.1.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^9.0.2" - yargs@^13.3.2: version "13.3.2" resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" @@ -21766,7 +19288,7 @@ yargs@^14.2.2: y18n "^4.0.0" yargs-parser "^15.0.1" -yargs@^15.0.0, yargs@^15.0.1, yargs@^15.3.1: +yargs@^15.3.1: version "15.3.1" resolved "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== @@ -21783,25 +19305,6 @@ yargs@^15.0.0, yargs@^15.0.1, yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.1" -yargs@^8.0.2: - version "8.0.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" - integrity sha1-YpmpBVsc78lp/355wdkY3Osiw2A= - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - yauzl@2.10.0, yauzl@^2.10.0: version "2.10.0" resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" From 9f50e7c1b46e07179a8a296276545cab6a63149e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 29 May 2020 11:33:53 +0200 Subject: [PATCH 22/31] packages,plugins: fix lint issues --- packages/backend/src/plugins/auth.ts | 2 +- packages/backend/src/plugins/catalog.ts | 5 ++- packages/backend/src/plugins/identity.ts | 2 +- packages/backend/src/plugins/scaffolder.ts | 2 +- packages/backend/src/plugins/sentry.ts | 2 +- .../core-api/src/app/AppThemeProvider.tsx | 10 ++--- .../FeatureCalloutCircular.tsx | 4 +- .../FeatureDiscovery/lib/usePortal.ts | 41 ++++++++++--------- .../FeatureDiscovery/lib/useShowCallout.ts | 2 +- .../ProgressBars/HorizontalProgress.tsx | 2 +- .../ComponentPage/ComponentPage.test.tsx | 13 +++++- .../ComponentPage/ComponentPage.tsx | 12 +++--- .../src/components/Settings/Settings.tsx | 2 +- .../BuildWithStepsPage/BuildWithStepsPage.tsx | 2 +- .../circleci/src/state/useBuildWithSteps.ts | 2 +- plugins/circleci/src/state/useBuilds.ts | 4 +- plugins/circleci/src/state/useSettings.ts | 40 +++++++++--------- .../src/components/AuditList/index.tsx | 2 +- .../SentryPluginWidget/SentryPluginWidget.tsx | 2 +- .../src/components/RadarComponent.tsx | 20 ++++----- 20 files changed, 93 insertions(+), 78 deletions(-) diff --git a/packages/backend/src/plugins/auth.ts b/packages/backend/src/plugins/auth.ts index c2e349f640..7cf9610dc2 100644 --- a/packages/backend/src/plugins/auth.ts +++ b/packages/backend/src/plugins/auth.ts @@ -17,6 +17,6 @@ import { createRouter } from '@backstage/plugin-auth-backend'; import { PluginEnvironment } from '../types'; -export default async function ({ logger }: PluginEnvironment) { +export default async function createPlugin({ logger }: PluginEnvironment) { return await createRouter({ logger }); } diff --git a/packages/backend/src/plugins/catalog.ts b/packages/backend/src/plugins/catalog.ts index 9f5315fa08..91cbd8c254 100644 --- a/packages/backend/src/plugins/catalog.ts +++ b/packages/backend/src/plugins/catalog.ts @@ -27,7 +27,10 @@ import { import { PluginEnvironment } from '../types'; import { EntityPolicies } from '@backstage/catalog-model'; -export default async function ({ logger, database }: PluginEnvironment) { +export default async function createPlugin({ + logger, + database, +}: PluginEnvironment) { const policy = new EntityPolicies(); const ingestion = new IngestionModels( new LocationReaders(), diff --git a/packages/backend/src/plugins/identity.ts b/packages/backend/src/plugins/identity.ts index 26276afd01..63a326965c 100644 --- a/packages/backend/src/plugins/identity.ts +++ b/packages/backend/src/plugins/identity.ts @@ -17,6 +17,6 @@ import { createRouter } from '@backstage/plugin-identity-backend'; import { PluginEnvironment } from '../types'; -export default async function ({ logger }: PluginEnvironment) { +export default async function createPlugin({ logger }: PluginEnvironment) { return await createRouter({ logger }); } diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index 311c9197aa..08e700bc74 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -21,7 +21,7 @@ import { } from '@backstage/plugin-scaffolder-backend'; import type { PluginEnvironment } from '../types'; -export default async function ({ logger }: PluginEnvironment) { +export default async function createPlugin({ logger }: PluginEnvironment) { const storage = new DiskStorage({ logger }); const templater = new CookieCutter(); diff --git a/packages/backend/src/plugins/sentry.ts b/packages/backend/src/plugins/sentry.ts index 34506ee3de..89ee153faf 100644 --- a/packages/backend/src/plugins/sentry.ts +++ b/packages/backend/src/plugins/sentry.ts @@ -17,6 +17,6 @@ import { createRouter } from '@backstage/plugin-sentry-backend'; import { Logger } from 'winston'; -export default async function (logger: Logger) { +export default async function createPlugin(logger: Logger) { return await createRouter(logger); } diff --git a/packages/core-api/src/app/AppThemeProvider.tsx b/packages/core-api/src/app/AppThemeProvider.tsx index 775d8293ba..6bbcaea93a 100644 --- a/packages/core-api/src/app/AppThemeProvider.tsx +++ b/packages/core-api/src/app/AppThemeProvider.tsx @@ -49,10 +49,6 @@ function resolveTheme( } const useShouldPreferDarkTheme = () => { - if (!window.matchMedia) { - return false; - } - const mediaQuery = useMemo( () => window.matchMedia('(prefers-color-scheme: dark)'), [], @@ -74,12 +70,16 @@ const useShouldPreferDarkTheme = () => { export const AppThemeProvider: FC<{}> = ({ children }) => { const appThemeApi = useApi(appThemeApiRef); - const shouldPreferDark = useShouldPreferDarkTheme(); const themeId = useObservable( appThemeApi.activeThemeId$(), appThemeApi.getActiveThemeId(), ); + // Browser feature detection won't change over time, so ignore lint rule + const shouldPreferDark = Boolean(window.matchMedia) + ? useShouldPreferDarkTheme() // eslint-disable-line react-hooks/rules-of-hooks + : false; + const appTheme = resolveTheme( themeId, shouldPreferDark, diff --git a/packages/core/src/components/FeatureDiscovery/FeatureCalloutCircular.tsx b/packages/core/src/components/FeatureDiscovery/FeatureCalloutCircular.tsx index a3b40d5b88..38e422dbcc 100644 --- a/packages/core/src/components/FeatureDiscovery/FeatureCalloutCircular.tsx +++ b/packages/core/src/components/FeatureDiscovery/FeatureCalloutCircular.tsx @@ -141,9 +141,9 @@ export const FeatureCalloutCircular: FC = ({ window.removeEventListener('resize', update); window.removeEventListener('scroll', update); }; - }, []); + }, [update]); - useLayoutEffect(update, [wrapperRef.current]); + useLayoutEffect(update, [wrapperRef.current, update]); if (!show) { return <>{children}; diff --git a/packages/core/src/components/FeatureDiscovery/lib/usePortal.ts b/packages/core/src/components/FeatureDiscovery/lib/usePortal.ts index 6031a25f1c..d5fd2c23c9 100644 --- a/packages/core/src/components/FeatureDiscovery/lib/usePortal.ts +++ b/packages/core/src/components/FeatureDiscovery/lib/usePortal.ts @@ -51,27 +51,30 @@ function addRootElement(rootElem: Element): void { export function usePortal(id: string): HTMLElement { const rootElemRef = useRef(null); - useEffect(function setupElement() { - // Look for existing target dom element to append to - const existingParent = document.querySelector(`#${id}`); - // Parent is either a new root or the existing dom element - const parentElem = existingParent || createRootElement(id); + useEffect( + function setupElement() { + // Look for existing target dom element to append to + const existingParent = document.querySelector(`#${id}`); + // Parent is either a new root or the existing dom element + const parentElem = existingParent || createRootElement(id); - // If there is no existing DOM element, add a new one. - if (!existingParent) { - addRootElement(parentElem); - } - - // Add the detached element to the parent - parentElem.appendChild(rootElemRef.current!); - - return function removeElement() { - rootElemRef.current!.remove(); - if (parentElem.childNodes.length === -1) { - parentElem.remove(); + // If there is no existing DOM element, add a new one. + if (!existingParent) { + addRootElement(parentElem); } - }; - }, []); + + // Add the detached element to the parent + parentElem.appendChild(rootElemRef.current!); + + return function removeElement() { + rootElemRef.current!.remove(); + if (parentElem.childNodes.length === -1) { + parentElem.remove(); + } + }; + }, + [id], + ); /** * It's important we evaluate this lazily: diff --git a/packages/core/src/components/FeatureDiscovery/lib/useShowCallout.ts b/packages/core/src/components/FeatureDiscovery/lib/useShowCallout.ts index 047473a7e2..0bbcf3b8ec 100644 --- a/packages/core/src/components/FeatureDiscovery/lib/useShowCallout.ts +++ b/packages/core/src/components/FeatureDiscovery/lib/useShowCallout.ts @@ -45,7 +45,7 @@ function useCalloutHasBeenSeen( const markSeen = useCallback(() => { setState(featureId, true); - }, [featureId]); + }, [setState, featureId]); return { seen: states[featureId] === true, markSeen }; } diff --git a/packages/core/src/components/ProgressBars/HorizontalProgress.tsx b/packages/core/src/components/ProgressBars/HorizontalProgress.tsx index 7575c5a9b2..d7f813f55f 100644 --- a/packages/core/src/components/ProgressBars/HorizontalProgress.tsx +++ b/packages/core/src/components/ProgressBars/HorizontalProgress.tsx @@ -29,6 +29,7 @@ type Props = { }; const HorizontalProgress: FC = ({ value }) => { + const theme = useTheme(); if (isNaN(value)) { return null; } @@ -36,7 +37,6 @@ const HorizontalProgress: FC = ({ value }) => { if (percent > 100) { percent = 100; } - const theme = useTheme(); const strokeColor = getProgressColor(theme.palette, percent, false, 100); return ( diff --git a/plugins/catalog/src/components/ComponentPage/ComponentPage.test.tsx b/plugins/catalog/src/components/ComponentPage/ComponentPage.test.tsx index e21c4dbce9..f580a84d8a 100644 --- a/plugins/catalog/src/components/ComponentPage/ComponentPage.test.tsx +++ b/plugins/catalog/src/components/ComponentPage/ComponentPage.test.tsx @@ -18,6 +18,7 @@ import { render } from '@testing-library/react'; import * as React from 'react'; import { wrapInTestApp } from '@backstage/test-utils'; import { ApiProvider, ApiRegistry, errorApiRef } from '@backstage/core'; +import { catalogApiRef, CatalogApi } from '../../api/types'; const getTestProps = (componentName: string) => { return { @@ -39,7 +40,17 @@ describe('ComponentPage', () => { const props = getTestProps(''); await render( wrapInTestApp( - + , ), diff --git a/plugins/catalog/src/components/ComponentPage/ComponentPage.tsx b/plugins/catalog/src/components/ComponentPage/ComponentPage.tsx index 0ee0e1d09a..62f34f1620 100644 --- a/plugins/catalog/src/components/ComponentPage/ComponentPage.tsx +++ b/plugins/catalog/src/components/ComponentPage/ComponentPage.tsx @@ -53,11 +53,6 @@ const ComponentPage: FC = ({ match, history }) => { const componentName = match.params.name; const errorApi = useApi(errorApiRef); - if (componentName === '') { - history.push('/catalog'); - return null; - } - const catalogApi = useApi(catalogApiRef); const catalogRequest = useAsync(() => catalogApi.getEntityByName(match.params.name), @@ -70,7 +65,12 @@ const ComponentPage: FC = ({ match, history }) => { history.push('/catalog'); }, REDIRECT_DELAY); } - }, [catalogRequest.error]); + }, [catalogRequest.error, errorApi, history]); + + if (componentName === '') { + history.push('/catalog'); + return null; + } const removeComponent = async () => { setConfirmationDialogOpen(false); diff --git a/plugins/circleci/src/components/Settings/Settings.tsx b/plugins/circleci/src/components/Settings/Settings.tsx index f0ed3f2ceb..8897c1eb40 100644 --- a/plugins/circleci/src/components/Settings/Settings.tsx +++ b/plugins/circleci/src/components/Settings/Settings.tsx @@ -52,7 +52,7 @@ const Settings = () => { if (repoFromStore !== repo) { setRepo(repoFromStore); } - }, [ownerFromStore, repoFromStore, tokenFromStore]); + }, [ownerFromStore, repoFromStore, tokenFromStore, token, owner, repo]); const [saved, setSaved] = useState(false); diff --git a/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx b/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx index 75d09610b5..77e6daf755 100644 --- a/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx +++ b/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx @@ -111,7 +111,7 @@ const BuildWithStepsView: FC<{}> = () => { useEffect(() => { startPolling(); return () => stopPolling(); - }, [buildId, settings]); + }, [buildId, settings, startPolling, stopPolling]); return ( <> diff --git a/plugins/circleci/src/state/useBuildWithSteps.ts b/plugins/circleci/src/state/useBuildWithSteps.ts index 7aba770851..8fa7fa896d 100644 --- a/plugins/circleci/src/state/useBuildWithSteps.ts +++ b/plugins/circleci/src/state/useBuildWithSteps.ts @@ -46,7 +46,7 @@ export function useBuildWithSteps(buildId: number) { errorApi.post(e); return Promise.reject(e); } - }, [token, owner, repo, buildId]); + }, [token, owner, repo, buildId, api, errorApi]); const restartBuild = async () => { try { diff --git a/plugins/circleci/src/state/useBuilds.ts b/plugins/circleci/src/state/useBuilds.ts index f90311b56b..6d38c5f901 100644 --- a/plugins/circleci/src/state/useBuilds.ts +++ b/plugins/circleci/src/state/useBuilds.ts @@ -101,7 +101,7 @@ export function useBuilds() { return Promise.reject(e); } }, - [repo, token, owner], + [repo, token, owner, api, errorApi], ); const restartBuild = async (buildId: number) => { @@ -121,7 +121,7 @@ export function useBuilds() { useEffect(() => { getBuilds({ limit: 1, offset: 0 }).then(b => setTotal(b?.[0].build_num!)); - }, [repo]); + }, [repo, getBuilds]); const { loading, value, retry } = useAsyncRetry( () => diff --git a/plugins/circleci/src/state/useSettings.ts b/plugins/circleci/src/state/useSettings.ts index c8dc9ce39b..3cc58a65bd 100644 --- a/plugins/circleci/src/state/useSettings.ts +++ b/plugins/circleci/src/state/useSettings.ts @@ -23,27 +23,29 @@ export function useSettings() { const errorApi = useApi(errorApiRef); - const rehydrate = () => { - try { - const stateFromStorage = JSON.parse(sessionStorage.getItem(STORAGE_KEY)!); - if ( - stateFromStorage && - Object.keys(stateFromStorage).some( - k => (settings as any)[k] !== stateFromStorage[k], - ) - ) - dispatch({ - type: 'setCredentials', - payload: stateFromStorage, - }); - } catch (error) { - errorApi.post(error); - } - }; - useEffect(() => { + const rehydrate = () => { + try { + const stateFromStorage = JSON.parse( + sessionStorage.getItem(STORAGE_KEY)!, + ); + if ( + stateFromStorage && + Object.keys(stateFromStorage).some( + k => (settings as any)[k] !== stateFromStorage[k], + ) + ) + dispatch({ + type: 'setCredentials', + payload: stateFromStorage, + }); + } catch (error) { + errorApi.post(error); + } + }; + rehydrate(); - }, []); + }, [dispatch, errorApi, settings]); const persist = (state: Settings) => { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state)); diff --git a/plugins/lighthouse/src/components/AuditList/index.tsx b/plugins/lighthouse/src/components/AuditList/index.tsx index 85be31cc80..4dbbb05295 100644 --- a/plugins/lighthouse/src/components/AuditList/index.tsx +++ b/plugins/lighthouse/src/components/AuditList/index.tsx @@ -63,7 +63,7 @@ const AuditList: FC<{}> = () => { if (value?.total && value?.limit) return Math.ceil(value?.total / value?.limit); return 0; - }, [value]); + }, [value?.total, value?.limit]); const history = useHistory(); diff --git a/plugins/sentry/src/components/SentryPluginWidget/SentryPluginWidget.tsx b/plugins/sentry/src/components/SentryPluginWidget/SentryPluginWidget.tsx index 5049905966..b101a9092a 100644 --- a/plugins/sentry/src/components/SentryPluginWidget/SentryPluginWidget.tsx +++ b/plugins/sentry/src/components/SentryPluginWidget/SentryPluginWidget.tsx @@ -43,7 +43,7 @@ export const SentryPluginWidget: FC<{ if (error) { errorApi.post(error); } - }, [error]); + }, [error, errorApi]); if (loading) { return ( diff --git a/plugins/tech-radar/src/components/RadarComponent.tsx b/plugins/tech-radar/src/components/RadarComponent.tsx index 7a6c4fedaf..981d1f1369 100644 --- a/plugins/tech-radar/src/components/RadarComponent.tsx +++ b/plugins/tech-radar/src/components/RadarComponent.tsx @@ -21,6 +21,7 @@ import { TechRadarComponentProps, TechRadarLoaderResponse } from '../api'; import getSampleData from '../sampleData'; const useTechRadarLoader = (props: TechRadarComponentProps) => { + const errorApi = useApi(errorApiRef); const [state, setState] = useState<{ loading: boolean; error?: Error; @@ -31,38 +32,33 @@ const useTechRadarLoader = (props: TechRadarComponentProps) => { data: undefined, }); + const { getData } = props; + useEffect(() => { - if (!props.getData) { + if (!getData) { return; } - props - .getData() + getData() .then((payload: TechRadarLoaderResponse) => { setState({ loading: false, error: undefined, data: payload }); }) .catch((err: Error) => { + errorApi.post(err); setState({ loading: false, error: err, data: undefined, }); }); - }, []); + }, [getData, errorApi]); return state; }; -const RadarComponent: FC = (props) => { - const errorApi = useApi(errorApiRef); +const RadarComponent: FC = props => { const { loading, error, data } = useTechRadarLoader(props); - useEffect(() => { - if (error) { - errorApi.post(error); - } - }, [error && error.message]); - return ( <> {loading && } From 7da845e844e9c2b81e2942d0c6a394f7ac933abb Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 29 May 2020 11:58:10 +0200 Subject: [PATCH 23/31] packages/cli: use own tsconfig --- packages/cli/config/tsconfig.json | 32 +++++++++++++++++++++++++------ packages/cli/package.json | 1 - tsconfig.json | 1 - yarn.lock | 5 ----- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/cli/config/tsconfig.json b/packages/cli/config/tsconfig.json index fb52420860..9f02bfcafe 100644 --- a/packages/cli/config/tsconfig.json +++ b/packages/cli/config/tsconfig.json @@ -1,17 +1,37 @@ { - "extends": "@spotify/tsconfig", - "exclude": ["**/*.test.*"], "compilerOptions": { "allowJs": true, - "noEmit": false, + "declaration": true, + "declarationMap": false, "emitDeclarationOnly": true, + "esModuleInterop": true, + "experimentalDecorators": false, + "forceConsistentCasingInFileNames": true, + "importHelpers": false, "incremental": true, - "target": "ES2019", + "isolatedModules": false, + "jsx": "react", + "lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2019"], "module": "ESNext", + "moduleResolution": "node", + "noEmit": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "pretty": true, "removeComments": false, "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2019"], + "sourceMap": false, + "strict": true, + "strictBindCallApply": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "stripInternal": true, + "target": "ES2019", "types": ["node", "jest"] } } diff --git a/packages/cli/package.json b/packages/cli/package.json index 13c0fd4aa3..20d9893a37 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -36,7 +36,6 @@ "@rollup/plugin-json": "^4.0.2", "@rollup/plugin-node-resolve": "^7.1.1", "@spotify/eslint-config": "^7.0.1", - "@spotify/tsconfig": "^7.0.0", "@sucrase/webpack-loader": "^2.0.0", "bfj": "^7.0.2", "chalk": "^4.0.0", diff --git a/tsconfig.json b/tsconfig.json index 52cdd1e825..2b36617ad9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "@backstage/cli/config/tsconfig.json", "include": ["packages/*/src", "plugins/*/src", "plugins/*/dev"], - "exclude": ["**/node_modules"], "compilerOptions": { "outDir": "dist" } diff --git a/yarn.lock b/yarn.lock index 679f75cb36..74fba61f49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2540,11 +2540,6 @@ resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-7.0.0.tgz#47750979d1282197295108b6958360660a955c16" integrity sha512-lIMcx/2oDqTtW84iHKkRJe+8U6HK6GPwWH5sJp9UEHcDpdXomOQYvwcGXy2I2zwPQQ14gYYE6nEJuSnnYqsYRw== -"@spotify/tsconfig@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@spotify/tsconfig/-/tsconfig-7.0.0.tgz#41c402f4eb6d3147bc18427a35205151cbb32cd5" - integrity sha512-MeRFUPMXWBSm6yaUWiESaQsF9B+9Rn1F/w5hbHHzcunc45teXBcgsOrJu1uDOEkhP/9lP0fefuodpP+TYWM1LQ== - "@spotify/web-scripts-utils@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@spotify/web-scripts-utils/-/web-scripts-utils-7.0.0.tgz#8c6b8039fc645a36ac48629eb9ba06600f4d828a" From f9e4e557f8bd5b81b28bfe5c19e76e8f4e720fb7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 29 May 2020 12:00:26 +0200 Subject: [PATCH 24/31] packages/cli: enable TS isolatedModules --- packages/catalog-model/src/kinds/index.ts | 7 ++++--- packages/catalog-model/src/setupTests.ts | 2 ++ packages/cli/config/tsconfig.json | 2 +- packages/cli/src/commands/lint.ts | 3 +-- .../src/providers/OAuthProvider.test.ts | 21 ------------------- .../auth-backend/src/providers/index.test.ts | 4 +++- 6 files changed, 11 insertions(+), 28 deletions(-) delete mode 100644 plugins/auth-backend/src/providers/OAuthProvider.test.ts diff --git a/packages/catalog-model/src/kinds/index.ts b/packages/catalog-model/src/kinds/index.ts index 97d22c14a5..ed79fed61d 100644 --- a/packages/catalog-model/src/kinds/index.ts +++ b/packages/catalog-model/src/kinds/index.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import type { ComponentV1beta1 } from './ComponentV1beta1'; +export type { + ComponentV1beta1, + ComponentV1beta1 as Component, +} from './ComponentV1beta1'; export { ComponentV1beta1Policy } from './ComponentV1beta1'; -export { ComponentV1beta1 as Component }; -export { ComponentV1beta1 }; diff --git a/packages/catalog-model/src/setupTests.ts b/packages/catalog-model/src/setupTests.ts index f3b69cc361..ba33cf996b 100644 --- a/packages/catalog-model/src/setupTests.ts +++ b/packages/catalog-model/src/setupTests.ts @@ -13,3 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +export {}; diff --git a/packages/cli/config/tsconfig.json b/packages/cli/config/tsconfig.json index 9f02bfcafe..f6d622ee16 100644 --- a/packages/cli/config/tsconfig.json +++ b/packages/cli/config/tsconfig.json @@ -9,7 +9,7 @@ "forceConsistentCasingInFileNames": true, "importHelpers": false, "incremental": true, - "isolatedModules": false, + "isolatedModules": true, "jsx": "react", "lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2019"], "module": "ESNext", diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts index 7eeedcbe29..41e69c51be 100644 --- a/packages/cli/src/commands/lint.ts +++ b/packages/cli/src/commands/lint.ts @@ -20,8 +20,7 @@ import { paths } from '../lib/paths'; export default async (cmd: Command) => { const args = [ - '--ext', - 'js,jsx,ts,tsx', + '--ext=js,jsx,ts,tsx', '--max-warnings=0', '--format=codeframe', paths.targetDir, diff --git a/plugins/auth-backend/src/providers/OAuthProvider.test.ts b/plugins/auth-backend/src/providers/OAuthProvider.test.ts deleted file mode 100644 index 308849057b..0000000000 --- a/plugins/auth-backend/src/providers/OAuthProvider.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -describe('OAuthProvider', () => { - it('unbreak test runner', () => { - expect(true).toBeTruthy(); - }); -}); diff --git a/plugins/auth-backend/src/providers/index.test.ts b/plugins/auth-backend/src/providers/index.test.ts index b3e2f19771..7f39d9de57 100644 --- a/plugins/auth-backend/src/providers/index.test.ts +++ b/plugins/auth-backend/src/providers/index.test.ts @@ -14,8 +14,10 @@ * limitations under the License. */ +import { defaultRouter } from '.'; + describe('test', () => { it('unbreaks the test runner', () => { - expect(true).toBeTruthy(); + expect(defaultRouter).toBeDefined(); }); }); From 067d44181bc1d907514c2aa763d48b52e7f50782 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 1 Jun 2020 17:00:50 +0200 Subject: [PATCH 25/31] scripts/check-type-dependencies: only verify type deps for packages that have been built --- scripts/check-type-dependencies.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/check-type-dependencies.js b/scripts/check-type-dependencies.js index 5b7daa13d2..6ee4626a21 100755 --- a/scripts/check-type-dependencies.js +++ b/scripts/check-type-dependencies.js @@ -69,7 +69,11 @@ async function main() { } function shouldCheckTypes(pkg) { - return !pkg.private && pkg.get('types'); + return ( + !pkg.private && + pkg.get('types') && + fs.existsSync(resolvePath(pkg.location, 'dist/index.d.ts')) + ); } /** From 2ee6f5d87fb96b9ab929df38689a3f7cbed5be34 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 1 Jun 2020 17:02:11 +0200 Subject: [PATCH 26/31] github/workflows: remove scripts from cli deps --- .github/workflows/cli.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 07ed78743c..24ff2a734c 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -6,7 +6,6 @@ on: - '.github/workflows/cli.yml' - 'packages/cli/**' - 'packages/core/**' - - 'scripts/**' - 'yarn.lock' jobs: From 5094dc75a51f973f1b635397813651bce18b5fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 1 Jun 2020 21:27:38 +0200 Subject: [PATCH 27/31] Add ability to specify locationId on addOrUpdateEntity --- .../src/catalog/DatabaseEntitiesCatalog.ts | 14 ++++++++++---- plugins/catalog-backend/src/catalog/types.ts | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts index d13ac9a1ba..606b6dc475 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts @@ -49,13 +49,16 @@ export class DatabaseEntitiesCatalog implements EntitiesCatalog { ); } - async addOrUpdateEntity(entity: Entity): Promise { + async addOrUpdateEntity( + entity: Entity, + locationId?: string, + ): Promise { await this.policy.enforce(entity); return await this.database.transaction(async tx => { let response: DbEntityResponse; if (entity.metadata.uid) { - response = await this.database.updateEntity(tx, { entity }); + response = await this.database.updateEntity(tx, { locationId, entity }); } else { const existing = await this.entityByNameInternal( tx, @@ -64,9 +67,12 @@ export class DatabaseEntitiesCatalog implements EntitiesCatalog { entity.metadata.namespace, ); if (existing) { - response = await this.database.updateEntity(tx, { entity }); + response = await this.database.updateEntity(tx, { + locationId, + entity, + }); } else { - response = await this.database.addEntity(tx, { entity }); + response = await this.database.addEntity(tx, { locationId, entity }); } } diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index 61fba33ebf..2ef5fd9e56 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -30,7 +30,7 @@ export type EntitiesCatalog = { namespace: string | undefined, name: string, ): Promise; - addOrUpdateEntity(entity: Entity): Promise; + addOrUpdateEntity(entity: Entity, locationId?: string): Promise; removeEntityByUid(uid: string): Promise; }; From f7ef6d492147449ecb9538f3166789c0df6d9580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 2 Jun 2020 09:32:45 +0200 Subject: [PATCH 28/31] Move addLocation to new HigherOrderOperations --- packages/backend/src/plugins/catalog.ts | 21 +- .../catalog/DatabaseEntitiesCatalog.test.ts | 13 +- .../src/catalog/DatabaseEntitiesCatalog.ts | 8 +- .../catalog/DatabaseLocationsCatalog.test.ts | 72 ++---- .../src/catalog/DatabaseLocationsCatalog.ts | 32 +-- plugins/catalog-backend/src/catalog/index.ts | 3 +- plugins/catalog-backend/src/catalog/types.ts | 22 +- .../src/database/CommonDatabase.test.ts | 47 ++-- .../src/database/CommonDatabase.ts | 28 +-- .../migrations/20200511113813_init.ts | 6 +- plugins/catalog-backend/src/database/types.ts | 16 +- .../src/ingestion/HigherOrderOperations.ts | 119 ++++++++++ .../catalog-backend/src/ingestion/index.ts | 1 + .../catalog-backend/src/ingestion/types.ts | 11 + .../src/service/router.test.ts | 208 +++++++----------- plugins/catalog-backend/src/service/router.ts | 31 ++- 16 files changed, 324 insertions(+), 314 deletions(-) create mode 100644 plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts diff --git a/packages/backend/src/plugins/catalog.ts b/packages/backend/src/plugins/catalog.ts index 91cbd8c254..150b9d1826 100644 --- a/packages/backend/src/plugins/catalog.ts +++ b/packages/backend/src/plugins/catalog.ts @@ -23,6 +23,7 @@ import { LocationReaders, IngestionModels, runPeriodically, + HigherOrderOperations, } from '@backstage/plugin-catalog-backend'; import { PluginEnvironment } from '../types'; import { EntityPolicies } from '@backstage/catalog-model'; @@ -32,7 +33,7 @@ export default async function createPlugin({ database, }: PluginEnvironment) { const policy = new EntityPolicies(); - const ingestion = new IngestionModels( + const ingestionModel = new IngestionModels( new LocationReaders(), new DescriptorParsers(), new EntityPolicies(), @@ -40,12 +41,22 @@ export default async function createPlugin({ const db = await DatabaseManager.createDatabase(database, logger); runPeriodically( - () => DatabaseManager.refreshLocations(db, ingestion, policy, logger), + () => DatabaseManager.refreshLocations(db, ingestionModel, policy, logger), 10000, ); - const entitiesCatalog = new DatabaseEntitiesCatalog(db, policy); - const locationsCatalog = new DatabaseLocationsCatalog(db, ingestion); + const entitiesCatalog = new DatabaseEntitiesCatalog(db); + const locationsCatalog = new DatabaseLocationsCatalog(db); + const higherOrderOperation = new HigherOrderOperations( + entitiesCatalog, + locationsCatalog, + ingestionModel, + ); - return await createRouter({ entitiesCatalog, locationsCatalog, logger }); + return await createRouter({ + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + logger, + }); } diff --git a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts index 1de5038112..b185075002 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts @@ -14,13 +14,12 @@ * limitations under the License. */ -import type { Entity, EntityPolicy } from '@backstage/catalog-model'; +import type { Entity } from '@backstage/catalog-model'; import type { Database } from '../database'; import { DatabaseEntitiesCatalog } from './DatabaseEntitiesCatalog'; describe('DatabaseEntitiesCatalog', () => { let db: jest.Mocked; - let policy: EntityPolicy; beforeEach(() => { db = { @@ -38,7 +37,6 @@ describe('DatabaseEntitiesCatalog', () => { addLocationUpdateLogEvent: jest.fn(), }; db.transaction.mockImplementation(async f => f('tx')); - policy = { enforce: jest.fn(async x => x) }; }); describe('addOrUpdateEntity', () => { @@ -55,10 +53,9 @@ describe('DatabaseEntitiesCatalog', () => { db.entities.mockResolvedValue([]); db.addEntity.mockResolvedValue({ entity }); - const catalog = new DatabaseEntitiesCatalog(db, policy); + const catalog = new DatabaseEntitiesCatalog(db); const result = await catalog.addOrUpdateEntity(entity); - expect(policy.enforce).toBeCalledWith(entity); expect(db.entities).toHaveBeenCalledTimes(1); expect(db.addEntity).toHaveBeenCalledTimes(1); expect(result).toBe(entity); @@ -78,10 +75,9 @@ describe('DatabaseEntitiesCatalog', () => { db.entities.mockResolvedValue([]); db.updateEntity.mockResolvedValue({ entity }); - const catalog = new DatabaseEntitiesCatalog(db, policy); + const catalog = new DatabaseEntitiesCatalog(db); const result = await catalog.addOrUpdateEntity(entity); - expect(policy.enforce).toBeCalledWith(entity); expect(db.entities).toHaveBeenCalledTimes(0); expect(db.updateEntity).toHaveBeenCalledTimes(1); expect(result).toBe(entity); @@ -108,10 +104,9 @@ describe('DatabaseEntitiesCatalog', () => { db.entities.mockResolvedValue([{ entity: existing }]); db.updateEntity.mockResolvedValue({ entity: added }); - const catalog = new DatabaseEntitiesCatalog(db, policy); + const catalog = new DatabaseEntitiesCatalog(db); const result = await catalog.addOrUpdateEntity(added); - expect(policy.enforce).toBeCalledWith(added); expect(db.entities).toHaveBeenCalledTimes(1); expect(db.updateEntity).toHaveBeenCalledTimes(1); expect(result).toEqual(existing); diff --git a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts index 606b6dc475..6a7a51a168 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts @@ -14,15 +14,12 @@ * limitations under the License. */ -import type { Entity, EntityPolicy } from '@backstage/catalog-model'; +import type { Entity } from '@backstage/catalog-model'; import type { Database, DbEntityResponse, EntityFilters } from '../database'; import type { EntitiesCatalog } from './types'; export class DatabaseEntitiesCatalog implements EntitiesCatalog { - constructor( - private readonly database: Database, - private readonly policy: EntityPolicy, - ) {} + constructor(private readonly database: Database) {} async entities(filters?: EntityFilters): Promise { const items = await this.database.transaction(tx => @@ -53,7 +50,6 @@ export class DatabaseEntitiesCatalog implements EntitiesCatalog { entity: Entity, locationId?: string, ): Promise { - await this.policy.enforce(entity); return await this.database.transaction(async tx => { let response: DbEntityResponse; diff --git a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts index 443b3bf6b0..907bdea2d5 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts @@ -13,73 +13,45 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { getVoidLogger } from '@backstage/backend-common'; -import type { Entity } from '@backstage/catalog-model'; import Knex from 'knex'; import path from 'path'; import { CommonDatabase } from '../database'; -import type { Database } from '../database'; -import type { IngestionModel } from '../ingestion/types'; import { DatabaseLocationsCatalog } from './DatabaseLocationsCatalog'; -class MockIngestionModel implements IngestionModel { - readLocation = jest.fn(async (type: string, target: string) => { - if (type !== 'valid_type') { - throw new Error(`Unknown location type ${type}`); - } - if (target === 'valid_target') { - return [{ type: 'data', data: {} as Entity } as const]; - } - throw new Error( - `Can't read location at ${target} with error: Something is broken`, - ); - }); -} - describe('DatabaseLocationsCatalog', () => { - const knex = Knex({ - client: 'sqlite3', - connection: ':memory:', - useNullAsDefault: true, - }); - knex.client.pool.on('createSuccess', (_eventId: any, resource: any) => { - resource.run('PRAGMA foreign_keys = ON', () => {}); - }); - let db: Database; let catalog: DatabaseLocationsCatalog; - let ingestionModel: IngestionModel; beforeEach(async () => { + const knex = Knex({ + client: 'sqlite3', + connection: ':memory:', + useNullAsDefault: true, + }); + knex.client.pool.on('createSuccess', (_eventId: any, resource: any) => { + resource.run('PRAGMA foreign_keys = ON', () => {}); + }); await knex.migrate.latest({ directory: path.resolve(__dirname, '../database/migrations'), loadExtensions: ['.ts'], }); - db = new CommonDatabase(knex, getVoidLogger()); - ingestionModel = new MockIngestionModel(); - catalog = new DatabaseLocationsCatalog(db, ingestionModel); + const db = new CommonDatabase(knex, getVoidLogger()); + catalog = new DatabaseLocationsCatalog(db); }); - it('resolves to location with id', async () => { - return expect( - catalog.addLocation({ type: 'valid_type', target: 'valid_target' }), - ).resolves.toEqual({ - id: expect.anything(), + it('can add a location', async () => { + const location = { + id: 'dd12620d-0436-422f-93bd-929aa0788123', type: 'valid_type', target: 'valid_target', - }); - }); - it('rejects for invalid type', async () => { - const type = 'invalid_type'; - return expect( - catalog.addLocation({ type, target: 'valid_target' }), - ).rejects.toThrow(/Unknown location type/); - }); - it('rejects for unreadable target ', async () => { - const target = 'invalid_target'; - return expect( - catalog.addLocation({ type: 'valid_type', target }), - ).rejects.toThrow( - `Can't read location at ${target} with error: Something is broken`, - ); + }; + await expect(catalog.addLocation(location)).resolves.toEqual(location); + await expect( + catalog.location('dd12620d-0436-422f-93bd-929aa0788123'), + ).resolves.toEqual(expect.objectContaining({ data: location })); + await expect(catalog.locations()).resolves.toEqual([ + expect.objectContaining({ data: location }), + ]); }); }); diff --git a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts index ae910e0b9b..2a5208c95a 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts @@ -16,38 +16,12 @@ import type { Database } from '../database'; import { DatabaseLocationUpdateLogEvent } from '../database/types'; -import { IngestionModel } from '../ingestion/types'; -import { - AddLocation, - Location, - LocationResponse, - LocationsCatalog, -} from './types'; +import { Location, LocationResponse, LocationsCatalog } from './types'; export class DatabaseLocationsCatalog implements LocationsCatalog { - constructor( - private readonly database: Database, - private readonly ingestionModel: IngestionModel, - ) {} - - async addLocation(location: AddLocation): Promise { - const outputs = await this.ingestionModel.readLocation( - location.type, - location.target, - ); - if (!outputs) { - throw new Error( - `Unknown location type ${location.type} ${location.target}`, - ); - } - outputs.forEach(output => { - if (output.type === 'error') { - throw new Error( - `Can't read location at ${location.target}, ${output.error}`, - ); - } - }); + constructor(private readonly database: Database) {} + async addLocation(location: Location): Promise { const added = await this.database.addLocation(location); return added; } diff --git a/plugins/catalog-backend/src/catalog/index.ts b/plugins/catalog-backend/src/catalog/index.ts index 6768268f34..dc0bb2e84a 100644 --- a/plugins/catalog-backend/src/catalog/index.ts +++ b/plugins/catalog-backend/src/catalog/index.ts @@ -17,10 +17,9 @@ export { DatabaseEntitiesCatalog } from './DatabaseEntitiesCatalog'; export { DatabaseLocationsCatalog } from './DatabaseLocationsCatalog'; export { StaticEntitiesCatalog } from './StaticEntitiesCatalog'; -export { addLocationSchema } from './types'; export type { - AddLocation, EntitiesCatalog, Location, LocationsCatalog, + LocationSpec, } from './types'; diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index 2ef5fd9e56..a8c3c7a15e 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -15,7 +15,6 @@ */ import { Entity } from '@backstage/catalog-model'; -import * as yup from 'yup'; import type { EntityFilters } from '../database'; // @@ -52,31 +51,22 @@ export type LocationUpdateLogEvent = { message?: string; }; -export type Location = { - id: string; +export type LocationSpec = { type: string; target: string; }; +export type Location = { + id: string; +} & LocationSpec; + export type LocationResponse = { data: Location; currentStatus: LocationUpdateStatus; }; -export type AddLocation = { - type: string; - target: string; -}; - -export const addLocationSchema: yup.Schema = yup - .object({ - type: yup.string().required(), - target: yup.string().required(), - }) - .noUnknown(); - export type LocationsCatalog = { - addLocation(location: AddLocation): Promise; + addLocation(location: Location): Promise; removeLocation(id: string): Promise; locations(): Promise; location(id: string): Promise; diff --git a/plugins/catalog-backend/src/database/CommonDatabase.test.ts b/plugins/catalog-backend/src/database/CommonDatabase.test.ts index 3b783a7691..8f62969bd1 100644 --- a/plugins/catalog-backend/src/database/CommonDatabase.test.ts +++ b/plugins/catalog-backend/src/database/CommonDatabase.test.ts @@ -22,13 +22,12 @@ import { import type { Entity } from '@backstage/catalog-model'; import Knex from 'knex'; import path from 'path'; +import { Location } from '../catalog'; import { CommonDatabase } from './CommonDatabase'; import { DatabaseLocationUpdateLogStatus } from './types'; import type { - AddDatabaseLocation, DbEntityRequest, DbEntityResponse, - DbLocationsRow, DbLocationsRowWithStatus, } from './types'; @@ -87,9 +86,13 @@ describe('CommonDatabase', () => { it('manages locations', async () => { const db = new CommonDatabase(knex, getVoidLogger()); - const input: AddDatabaseLocation = { type: 'a', target: 'b' }; + const input: Location = { + id: 'dd12620d-0436-422f-93bd-929aa0788123', + type: 'a', + target: 'b', + }; const output: DbLocationsRowWithStatus = { - id: expect.anything(), + id: 'dd12620d-0436-422f-93bd-929aa0788123', type: 'a', target: 'b', message: null, @@ -112,22 +115,6 @@ describe('CommonDatabase', () => { ); }); - it('instead of adding second location with the same target, returns existing one', async () => { - // Prepare - const catalog = new CommonDatabase(knex, getVoidLogger()); - const input: AddDatabaseLocation = { type: 'a', target: 'b' }; - const output1: DbLocationsRow = await catalog.addLocation(input); - - // Try to insert the same location - const output2: DbLocationsRow = await catalog.addLocation(input); - const locations = await catalog.locations(); - - // Output is the same - expect(output2).toEqual(output1); - // Locations contain only one record - expect(locations[0]).toMatchObject(output1); - }); - describe('addEntity', () => { it('happy path: adds entity to empty database', async () => { const catalog = new CommonDatabase(knex, getVoidLogger()); @@ -160,27 +147,33 @@ describe('CommonDatabase', () => { describe('locationHistory', () => { it('outputs the history correctly', async () => { const catalog = new CommonDatabase(knex, getVoidLogger()); - const location: AddDatabaseLocation = { type: 'a', target: 'b' }; - const { id: locationId } = await catalog.addLocation(location); + const location: Location = { + id: 'dd12620d-0436-422f-93bd-929aa0788123', + type: 'a', + target: 'b', + }; + await catalog.addLocation(location); await catalog.addLocationUpdateLogEvent( - locationId, + 'dd12620d-0436-422f-93bd-929aa0788123', DatabaseLocationUpdateLogStatus.SUCCESS, ); await catalog.addLocationUpdateLogEvent( - locationId, + 'dd12620d-0436-422f-93bd-929aa0788123', DatabaseLocationUpdateLogStatus.FAIL, undefined, 'Something went wrong', ); - const result = await catalog.locationHistory(locationId); + const result = await catalog.locationHistory( + 'dd12620d-0436-422f-93bd-929aa0788123', + ); expect(result).toEqual([ { created_at: expect.anything(), entity_name: null, id: expect.anything(), - location_id: locationId, + location_id: 'dd12620d-0436-422f-93bd-929aa0788123', message: null, status: DatabaseLocationUpdateLogStatus.SUCCESS, }, @@ -188,7 +181,7 @@ describe('CommonDatabase', () => { created_at: expect.anything(), entity_name: null, id: expect.anything(), - location_id: locationId, + location_id: 'dd12620d-0436-422f-93bd-929aa0788123', message: 'Something went wrong', status: DatabaseLocationUpdateLogStatus.FAIL, }, diff --git a/plugins/catalog-backend/src/database/CommonDatabase.ts b/plugins/catalog-backend/src/database/CommonDatabase.ts index 2dac08b9bc..084f6ea662 100644 --- a/plugins/catalog-backend/src/database/CommonDatabase.ts +++ b/plugins/catalog-backend/src/database/CommonDatabase.ts @@ -26,7 +26,6 @@ import { v4 as uuidv4 } from 'uuid'; import type { Logger } from 'winston'; import { buildEntitySearch } from './search'; import type { - AddDatabaseLocation, Database, DatabaseLocationUpdateLogEvent, DatabaseLocationUpdateLogStatus, @@ -38,6 +37,7 @@ import type { DbLocationsRowWithStatus, EntityFilters, } from './types'; +import { Location } from '../catalog'; function getStrippedMetadata(metadata: EntityMeta): EntityMeta { const output = lodash.cloneDeep(metadata); @@ -336,25 +336,15 @@ export class CommonDatabase implements Database { } } - async addLocation(location: AddDatabaseLocation): Promise { + async addLocation(location: Location): Promise { return await this.database.transaction(async tx => { - const existingLocation = await tx('locations') - .where({ target: location.target }) - .select(); - - if (existingLocation?.[0]) { - return existingLocation[0]; - } - - const id = uuidv4(); - const { type, target } = location; - await tx('locations').insert({ - id, - type, - target, - }); - - return (await tx('locations').where({ id }).select())![0]; + const row: DbLocationsRow = { + id: location.id, + type: location.type, + target: location.target, + }; + await tx('locations').insert(row); + return row; }); } diff --git a/plugins/catalog-backend/src/database/migrations/20200511113813_init.ts b/plugins/catalog-backend/src/database/migrations/20200511113813_init.ts index 2ff06c4046..5f136670f4 100644 --- a/plugins/catalog-backend/src/database/migrations/20200511113813_init.ts +++ b/plugins/catalog-backend/src/database/migrations/20200511113813_init.ts @@ -26,7 +26,11 @@ export async function up(knex: Knex): Promise { table.comment( 'Registered locations that shall be contiuously scanned for catalog item updates', ); - table.uuid('id').primary().comment('Auto-generated ID of the location'); + table + .uuid('id') + .primary() + .notNullable() + .comment('Auto-generated ID of the location'); table.string('type').notNullable().comment('The type of location'); table .string('target') diff --git a/plugins/catalog-backend/src/database/types.ts b/plugins/catalog-backend/src/database/types.ts index f69a7353c7..4bcc66af1c 100644 --- a/plugins/catalog-backend/src/database/types.ts +++ b/plugins/catalog-backend/src/database/types.ts @@ -15,7 +15,7 @@ */ import type { Entity } from '@backstage/catalog-model'; -import * as yup from 'yup'; +import { Location } from '../catalog'; export type DbEntitiesRow = { id: string; @@ -58,18 +58,6 @@ export type DbLocationsRowWithStatus = DbLocationsRow & { message: string | null; }; -export type AddDatabaseLocation = { - type: string; - target: string; -}; - -export const addDatabaseLocationSchema: yup.Schema = yup - .object({ - type: yup.string().required(), - target: yup.string().required(), - }) - .noUnknown(); - export enum DatabaseLocationUpdateLogStatus { FAIL = 'fail', SUCCESS = 'success', @@ -145,7 +133,7 @@ export type Database = { removeEntity(tx: unknown, uid: string): Promise; - addLocation(location: AddDatabaseLocation): Promise; + addLocation(location: Location): Promise; removeLocation(id: string): Promise; diff --git a/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts b/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts new file mode 100644 index 0000000000..0314556e27 --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts @@ -0,0 +1,119 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/backend-common'; +import { Entity } from '@backstage/catalog-model'; +import { v4 as uuidv4 } from 'uuid'; +import { + EntitiesCatalog, + Location, + LocationsCatalog, + LocationSpec, +} from '../catalog'; +import { IngestionModel } from '../ingestion'; +import { AddLocationResult, HigherOrderOperation } from './types'; + +const LOCATION_ANNOTATION = 'backstage.io/managed-by-location'; + +/** + * Placeholder for operations that span several catalogs and/or stretches out + * in time. + * + * TODO(freben): Find a better home for these, possibly refactoring to use the + * database more directly. + */ +export class HigherOrderOperations implements HigherOrderOperation { + private readonly entitiesCatalog: EntitiesCatalog; + private readonly locationsCatalog: LocationsCatalog; + private readonly ingestionModel: IngestionModel; + + constructor( + entitiesCatalog: EntitiesCatalog, + locationsCatalog: LocationsCatalog, + ingestionModel: IngestionModel, + ) { + this.entitiesCatalog = entitiesCatalog; + this.locationsCatalog = locationsCatalog; + this.ingestionModel = ingestionModel; + } + + /** + * Adds a single location to the catalog. + * + * The location is inspected and fetched, and all of the resulting data is + * validated. If everything goes well, the location and entities are stored + * in the catalog. + * + * If the location already existed, the old location is returned instead and + * the catalog is left unchanged. + * + * @param spec The location to add + */ + async addLocation(spec: LocationSpec): Promise { + // Attempt to find a previous location matching the spec + const previousLocations = await this.locationsCatalog.locations(); + const previousLocation = previousLocations.find( + l => spec.type === l.data.type && spec.target === l.data.target, + ); + const location: Location = previousLocation + ? previousLocation.data + : { + id: uuidv4(), + type: spec.type, + target: spec.target, + }; + + // Read the location fully, bailing on any errors + const readerOutput = await this.ingestionModel.readLocation( + location.type, + location.target, + ); + const inputEntities: Entity[] = []; + for (const entry of readerOutput) { + if (entry.type === 'error') { + throw new InputError( + `Failed to read location ${location.type} ${location.target}, ${entry.error}`, + ); + } else { + // Append the location reference annotation + entry.data.metadata.annotations = { + ...entry.data.metadata.annotations, + [LOCATION_ANNOTATION]: location.id, + }; + inputEntities.push(entry.data); + } + } + + // TODO(freben): At this point, we could detect orphaned entities, by way + // of having a LOCATION_ANNOTATION pointing to the location but not being + // in the entities list. But we aren't sure what to do about those yet. + + // Write + if (!previousLocation) { + await this.locationsCatalog.addLocation(location); + } + const outputEntities: Entity[] = []; + for (const entity of inputEntities) { + const out = await this.entitiesCatalog.addOrUpdateEntity( + entity, + location.id, + ); + outputEntities.push(out); + } + + return { location, entities: outputEntities }; + } +} diff --git a/plugins/catalog-backend/src/ingestion/index.ts b/plugins/catalog-backend/src/ingestion/index.ts index b6aceaecdd..93af856656 100644 --- a/plugins/catalog-backend/src/ingestion/index.ts +++ b/plugins/catalog-backend/src/ingestion/index.ts @@ -15,6 +15,7 @@ */ export * from './descriptor'; +export { HigherOrderOperations } from './HigherOrderOperations'; export { IngestionModels } from './IngestionModels'; export * from './source'; export type { IngestionModel } from './types'; diff --git a/plugins/catalog-backend/src/ingestion/types.ts b/plugins/catalog-backend/src/ingestion/types.ts index 8878c2af5b..45dd0d9f74 100644 --- a/plugins/catalog-backend/src/ingestion/types.ts +++ b/plugins/catalog-backend/src/ingestion/types.ts @@ -14,8 +14,19 @@ * limitations under the License. */ +import { Entity } from '@backstage/catalog-model'; +import { Location, LocationSpec } from '../catalog'; import { ReaderOutput } from './descriptor/parsers/types'; +export type AddLocationResult = { + location: Location; + entities: Entity[]; +}; + export type IngestionModel = { readLocation(type: string, target: string): Promise; }; + +export type HigherOrderOperation = { + addLocation(spec: LocationSpec): Promise; +}; diff --git a/plugins/catalog-backend/src/service/router.test.ts b/plugins/catalog-backend/src/service/router.test.ts index 4092ed1395..e03cb3dc98 100644 --- a/plugins/catalog-backend/src/service/router.test.ts +++ b/plugins/catalog-backend/src/service/router.test.ts @@ -18,42 +18,52 @@ import { getVoidLogger, NotFoundError } from '@backstage/backend-common'; import type { Entity } from '@backstage/catalog-model'; import express from 'express'; import request from 'supertest'; -import { EntitiesCatalog, Location, LocationsCatalog } from '../catalog'; +import { EntitiesCatalog, LocationsCatalog, LocationSpec } from '../catalog'; +import { LocationResponse } from '../catalog/types'; +import { HigherOrderOperation } from '../ingestion/types'; import { createRouter } from './router'; -class MockEntitiesCatalog implements EntitiesCatalog { - entities = jest.fn(); - entityByUid = jest.fn(); - entityByName = jest.fn(); - addEntity = jest.fn(); - addOrUpdateEntity = jest.fn(); - removeEntityByUid = jest.fn(); -} - -class MockLocationsCatalog implements LocationsCatalog { - addLocation = jest.fn(); - removeLocation = jest.fn(); - locations = jest.fn(); - location = jest.fn(); - locationHistory = jest.fn(); -} - describe('createRouter', () => { + let entitiesCatalog: jest.Mocked; + let locationsCatalog: jest.Mocked; + let higherOrderOperation: jest.Mocked; + let app: express.Express; + + beforeEach(async () => { + entitiesCatalog = { + entities: jest.fn(), + entityByUid: jest.fn(), + entityByName: jest.fn(), + addOrUpdateEntity: jest.fn(), + removeEntityByUid: jest.fn(), + }; + locationsCatalog = { + addLocation: jest.fn(), + removeLocation: jest.fn(), + locations: jest.fn(), + location: jest.fn(), + locationHistory: jest.fn(), + }; + higherOrderOperation = { + addLocation: jest.fn(), + }; + const router = await createRouter({ + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + logger: getVoidLogger(), + }); + app = express().use(router); + }); + describe('GET /entities', () => { it('happy path: lists entities', async () => { const entities: Entity[] = [ { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, ]; - const catalog = new MockEntitiesCatalog(); - catalog.entities.mockResolvedValueOnce(entities); + entitiesCatalog.entities.mockResolvedValueOnce(entities); - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app).get('/entities'); expect(response.status).toEqual(200); @@ -61,18 +71,10 @@ describe('createRouter', () => { }); it('parses single and multiple request parameters and passes them down', async () => { - const catalog = new MockEntitiesCatalog(); - - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app).get('/entities?a=1&a=&a=3&b=4&c='); expect(response.status).toEqual(200); - expect(catalog.entities).toHaveBeenCalledWith([ + expect(entitiesCatalog.entities).toHaveBeenCalledWith([ { key: 'a', values: ['1', null, '3'] }, { key: 'b', values: ['4'] }, { key: 'c', values: [null] }, @@ -89,15 +91,8 @@ describe('createRouter', () => { name: 'c', }, }; - const catalog = new MockEntitiesCatalog(); - catalog.entityByUid.mockResolvedValue(entity); + entitiesCatalog.entityByUid.mockResolvedValue(entity); - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app).get('/entities/by-uid/zzz'); expect(response.status).toEqual(200); @@ -105,15 +100,7 @@ describe('createRouter', () => { }); it('responds with a 404 for missing entities', async () => { - const catalog = new MockEntitiesCatalog(); - catalog.entityByUid.mockResolvedValue(undefined); - - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); + entitiesCatalog.entityByUid.mockResolvedValue(undefined); const response = await request(app).get('/entities/by-uid/zzz'); expect(response.status).toEqual(404); @@ -131,15 +118,8 @@ describe('createRouter', () => { namespace: 'd', }, }; - const catalog = new MockEntitiesCatalog(); - catalog.entityByName.mockResolvedValue(entity); + entitiesCatalog.entityByName.mockResolvedValue(entity); - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app).get('/entities/by-name/b/d/c'); expect(response.status).toEqual(200); @@ -147,15 +127,8 @@ describe('createRouter', () => { }); it('responds with a 404 for missing entities', async () => { - const catalog = new MockEntitiesCatalog(); - catalog.entityByName.mockResolvedValue(undefined); + entitiesCatalog.entityByName.mockResolvedValue(undefined); - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app).get('/entities/by-name//b/d/c'); expect(response.status).toEqual(404); @@ -165,13 +138,6 @@ describe('createRouter', () => { describe('POST /entities', () => { it('requires a body', async () => { - const catalog = new MockEntitiesCatalog(); - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app) .post('/entities') .set('Content-Type', 'application/json') @@ -179,7 +145,7 @@ describe('createRouter', () => { expect(response.status).toEqual(400); expect(response.text).toMatch(/body/); - expect(catalog.addOrUpdateEntity).not.toHaveBeenCalled(); + expect(entitiesCatalog.addOrUpdateEntity).not.toHaveBeenCalled(); }); it('passes the body down', async () => { @@ -192,15 +158,8 @@ describe('createRouter', () => { }, }; - const catalog = new MockEntitiesCatalog(); - catalog.addOrUpdateEntity.mockResolvedValue(entity); + entitiesCatalog.addOrUpdateEntity.mockResolvedValue(entity); - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app) .post('/entities') .send(entity) @@ -208,58 +167,46 @@ describe('createRouter', () => { expect(response.status).toEqual(200); expect(response.body).toEqual(entity); - expect(catalog.addOrUpdateEntity).toHaveBeenCalledTimes(1); - expect(catalog.addOrUpdateEntity).toHaveBeenNthCalledWith(1, entity); + expect(entitiesCatalog.addOrUpdateEntity).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.addOrUpdateEntity).toHaveBeenNthCalledWith( + 1, + entity, + ); }); }); describe('DELETE /entities/by-uid/:uid', () => { it('can remove', async () => { - const catalog = new MockEntitiesCatalog(); - catalog.removeEntityByUid.mockResolvedValue(undefined); + entitiesCatalog.removeEntityByUid.mockResolvedValue(undefined); - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app).delete('/entities/by-uid/apa'); expect(response.status).toEqual(204); - expect(catalog.removeEntityByUid).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.removeEntityByUid).toHaveBeenCalledTimes(1); }); it('responds with a 404 for missing entities', async () => { - const catalog = new MockEntitiesCatalog(); - catalog.removeEntityByUid.mockRejectedValue(new NotFoundError('nope')); + entitiesCatalog.removeEntityByUid.mockRejectedValue( + new NotFoundError('nope'), + ); - const router = await createRouter({ - entitiesCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app).delete('/entities/by-uid/apa'); expect(response.status).toEqual(404); - expect(catalog.removeEntityByUid).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.removeEntityByUid).toHaveBeenCalledTimes(1); }); }); describe('GET /locations', () => { it('happy path: lists locations', async () => { - const locations: Location[] = [{ id: 'a', type: 'b', target: 'c' }]; + const locations: LocationResponse[] = [ + { + currentStatus: { timestamp: '', status: '', message: '' }, + data: { id: 'a', type: 'b', target: 'c' }, + }, + ]; + locationsCatalog.locations.mockResolvedValueOnce(locations); - const catalog = new MockLocationsCatalog(); - catalog.locations.mockResolvedValueOnce(locations); - - const router = await createRouter({ - locationsCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); const response = await request(app).get('/locations'); expect(response.status).toEqual(200); @@ -269,22 +216,33 @@ describe('createRouter', () => { describe('POST /locations', () => { it('rejects malformed locations', async () => { - const location = ({ - id: 'a', + const spec = ({ typez: 'b', target: 'c', - } as unknown) as Location; + } as unknown) as LocationSpec; - const catalog = new MockLocationsCatalog(); - const router = await createRouter({ - locationsCatalog: catalog, - logger: getVoidLogger(), - }); - - const app = express().use(router); - const response = await request(app).post('/locations').send(location); + const response = await request(app).post('/locations').send(spec); expect(response.status).toEqual(400); + expect(higherOrderOperation.addLocation).not.toHaveBeenCalled(); + }); + + it('passes the body down', async () => { + const spec: LocationSpec = { + type: 'b', + target: 'c', + }; + + higherOrderOperation.addLocation.mockResolvedValue({ + location: { id: 'a', ...spec }, + entities: [], + }); + + const response = await request(app).post('/locations').send(spec); + + expect(response.status).toEqual(201); + expect(higherOrderOperation.addLocation).toHaveBeenCalledTimes(1); + expect(higherOrderOperation.addLocation).toHaveBeenCalledWith(spec); }); }); }); diff --git a/plugins/catalog-backend/src/service/router.ts b/plugins/catalog-backend/src/service/router.ts index f5adbd84ca..95ea068f58 100644 --- a/plugins/catalog-backend/src/service/router.ts +++ b/plugins/catalog-backend/src/service/router.ts @@ -19,24 +19,30 @@ import { Entity } from '@backstage/catalog-model'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; -import { - addLocationSchema, - EntitiesCatalog, - LocationsCatalog, -} from '../catalog'; +import * as yup from 'yup'; +import { EntitiesCatalog, LocationsCatalog, LocationSpec } from '../catalog'; import { EntityFilters } from '../database'; +import { HigherOrderOperation } from '../ingestion/types'; import { requireRequestBody, validateRequestBody } from './util'; export interface RouterOptions { entitiesCatalog?: EntitiesCatalog; locationsCatalog?: LocationsCatalog; + higherOrderOperation?: HigherOrderOperation; logger: Logger; } +const addLocationSchema = yup + .object({ + type: yup.string().required(), + target: yup.string().required(), + }) + .noUnknown(); + export async function createRouter( options: RouterOptions, ): Promise { - const { entitiesCatalog, locationsCatalog } = options; + const { entitiesCatalog, locationsCatalog, higherOrderOperation } = options; const router = Router(); router.use(express.json()); @@ -84,13 +90,16 @@ export async function createRouter( }); } + if (higherOrderOperation) { + router.post('/locations', async (req, res) => { + const input = await validateRequestBody(req, addLocationSchema); + const output = await higherOrderOperation.addLocation(input); + res.status(201).send(output); + }); + } + if (locationsCatalog) { router - .post('/locations', async (req, res) => { - const input = await validateRequestBody(req, addLocationSchema); - const output = await locationsCatalog.addLocation(input); - res.status(201).send(output); - }) .get('/locations', async (_req, res) => { const output = await locationsCatalog.locations(); res.status(200).send(output); From 9db24c79b80625626df5d09c93f12b083462b451 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2020 09:46:12 +0200 Subject: [PATCH 29/31] build(deps): bump ts-jest from 26.0.0 to 26.1.0 (#1099) Bumps [ts-jest](https://github.com/kulshekhar/ts-jest) from 26.0.0 to 26.1.0. - [Release notes](https://github.com/kulshekhar/ts-jest/releases) - [Changelog](https://github.com/kulshekhar/ts-jest/blob/master/CHANGELOG.md) - [Commits](https://github.com/kulshekhar/ts-jest/compare/v26.0.0...v26.1.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/yarn.lock b/yarn.lock index 74fba61f49..b322cb1da4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18024,9 +18024,9 @@ ts-invariant@^0.4.0: tslib "^1.9.3" ts-jest@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.0.0.tgz#957b802978249aaf74180b9dcb17b4fd787ad6f3" - integrity sha512-eBpWH65mGgzobuw7UZy+uPP9lwu+tPp60o324ASRX4Ijg8UC5dl2zcge4kkmqr2Zeuk9FwIjvCTOPuNMEyGWWw== + version "26.1.0" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.1.0.tgz#e9070fc97b3ea5557a48b67c631c74eb35e15417" + integrity sha512-JbhQdyDMYN5nfKXaAwCIyaWLGwevcT2/dbqRPsQeh6NZPUuXjZQZEfeLb75tz0ubCIgEELNm6xAzTe5NXs5Y4Q== dependencies: bs-logger "0.x" buffer-from "1.x" @@ -19211,7 +19211,7 @@ yaml@^1.7.2: dependencies: "@babel/runtime" "^7.8.7" -yargs-parser@18.x: +yargs-parser@18.x, yargs-parser@^18.1.1: version "18.1.3" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== @@ -19242,14 +19242,6 @@ yargs-parser@^15.0.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^18.1.1: - version "18.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.1.tgz#bf7407b915427fc760fcbbccc6c82b4f0ffcbd37" - integrity sha512-KRHEsOM16IX7XuLnMOqImcPNbLVXMNHYAoFc3BKR8Ortl5gzDbtXvvEoGx9imk5E+X1VeNKNlcHr8B8vi+7ipA== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs@^13.3.2: version "13.3.2" resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" From 7d4c044d1a58923916e0d296e6ed7656d00da689 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Tue, 2 Jun 2020 10:04:20 +0200 Subject: [PATCH 30/31] Rename test to clarify what it is doing --- .../src/apis/implementations/auth/github/GithubAuth.test.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/core-api/src/apis/implementations/auth/github/GithubAuth.test.ts b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.test.ts index 3d3da266fc..7c8e6ce9f0 100644 --- a/packages/core-api/src/apis/implementations/auth/github/GithubAuth.test.ts +++ b/packages/core-api/src/apis/implementations/auth/github/GithubAuth.test.ts @@ -16,13 +16,11 @@ import GithubAuth from './GithubAuth'; -const theFuture = new Date(Date.now() + 3600000); - describe('GithubAuth', () => { - it('should get refreshed access token', async () => { + it('should get access token', async () => { const getSession = jest .fn() - .mockResolvedValue({ accessToken: 'access-token', expiresAt: theFuture }); + .mockResolvedValue({ accessToken: 'access-token' }); const githubAuth = new GithubAuth({ getSession } as any); expect(await githubAuth.getAccessToken()).toBe('access-token'); From 8d0e750bc2ab32676214645aeb8c5699b7dd66a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 2 Jun 2020 10:49:23 +0200 Subject: [PATCH 31/31] Address comments and add tests --- packages/catalog-model/src/index.ts | 1 + packages/catalog-model/src/location/index.ts | 18 +++ packages/catalog-model/src/location/types.ts | 24 +++ .../catalog-model/src/location/validation.ts | 33 ++++ .../catalog/DatabaseEntitiesCatalog.test.ts | 6 +- .../src/catalog/DatabaseLocationsCatalog.ts | 3 +- plugins/catalog-backend/src/catalog/index.ts | 7 +- plugins/catalog-backend/src/catalog/types.ts | 11 +- .../src/database/CommonDatabase.test.ts | 3 +- .../src/database/CommonDatabase.ts | 3 +- plugins/catalog-backend/src/database/types.ts | 3 +- .../ingestion/HigherOrderOperations.test.ts | 143 ++++++++++++++++++ .../src/ingestion/HigherOrderOperations.ts | 9 +- .../catalog-backend/src/ingestion/types.ts | 5 +- .../src/service/router.test.ts | 10 +- plugins/catalog-backend/src/service/router.ts | 15 +- 16 files changed, 246 insertions(+), 48 deletions(-) create mode 100644 packages/catalog-model/src/location/index.ts create mode 100644 packages/catalog-model/src/location/types.ts create mode 100644 packages/catalog-model/src/location/validation.ts create mode 100644 plugins/catalog-backend/src/ingestion/HigherOrderOperations.test.ts diff --git a/packages/catalog-model/src/index.ts b/packages/catalog-model/src/index.ts index fb51461053..f149b8c9b4 100644 --- a/packages/catalog-model/src/index.ts +++ b/packages/catalog-model/src/index.ts @@ -17,5 +17,6 @@ export * from './entity'; export { EntityPolicies } from './EntityPolicies'; export * from './kinds'; +export * from './location'; export type { EntityPolicy } from './types'; export * from './validation'; diff --git a/packages/catalog-model/src/location/index.ts b/packages/catalog-model/src/location/index.ts new file mode 100644 index 0000000000..60465bff9b --- /dev/null +++ b/packages/catalog-model/src/location/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { Location, LocationSpec } from './types'; +export { locationSchema, locationSpecSchema } from './validation'; diff --git a/packages/catalog-model/src/location/types.ts b/packages/catalog-model/src/location/types.ts new file mode 100644 index 0000000000..50e6e82a54 --- /dev/null +++ b/packages/catalog-model/src/location/types.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type LocationSpec = { + type: string; + target: string; +}; + +export type Location = { + id: string; +} & LocationSpec; diff --git a/packages/catalog-model/src/location/validation.ts b/packages/catalog-model/src/location/validation.ts new file mode 100644 index 0000000000..5fad47bdd0 --- /dev/null +++ b/packages/catalog-model/src/location/validation.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as yup from 'yup'; +import { LocationSpec, Location } from './types'; + +export const locationSpecSchema = yup + .object({ + type: yup.string().required(), + target: yup.string().required(), + }) + .noUnknown(); + +export const locationSchema = yup + .object({ + id: yup.string().required(), + type: yup.string().required(), + target: yup.string().required(), + }) + .noUnknown(); diff --git a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts index b185075002..eb9cb2439c 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.test.ts @@ -21,7 +21,7 @@ import { DatabaseEntitiesCatalog } from './DatabaseEntitiesCatalog'; describe('DatabaseEntitiesCatalog', () => { let db: jest.Mocked; - beforeEach(() => { + beforeAll(() => { db = { transaction: jest.fn(), addEntity: jest.fn(), @@ -36,6 +36,10 @@ describe('DatabaseEntitiesCatalog', () => { locationHistory: jest.fn(), addLocationUpdateLogEvent: jest.fn(), }; + }); + + beforeEach(() => { + jest.resetAllMocks(); db.transaction.mockImplementation(async f => f('tx')); }); diff --git a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts index 2a5208c95a..066fab8464 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts @@ -14,9 +14,10 @@ * limitations under the License. */ +import { Location } from '@backstage/catalog-model'; import type { Database } from '../database'; import { DatabaseLocationUpdateLogEvent } from '../database/types'; -import { Location, LocationResponse, LocationsCatalog } from './types'; +import { LocationResponse, LocationsCatalog } from './types'; export class DatabaseLocationsCatalog implements LocationsCatalog { constructor(private readonly database: Database) {} diff --git a/plugins/catalog-backend/src/catalog/index.ts b/plugins/catalog-backend/src/catalog/index.ts index dc0bb2e84a..308078b1fc 100644 --- a/plugins/catalog-backend/src/catalog/index.ts +++ b/plugins/catalog-backend/src/catalog/index.ts @@ -17,9 +17,4 @@ export { DatabaseEntitiesCatalog } from './DatabaseEntitiesCatalog'; export { DatabaseLocationsCatalog } from './DatabaseLocationsCatalog'; export { StaticEntitiesCatalog } from './StaticEntitiesCatalog'; -export type { - EntitiesCatalog, - Location, - LocationsCatalog, - LocationSpec, -} from './types'; +export type { EntitiesCatalog, LocationsCatalog } from './types'; diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index a8c3c7a15e..0499b8a409 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; +import { Entity, Location } from '@backstage/catalog-model'; import type { EntityFilters } from '../database'; // @@ -51,15 +51,6 @@ export type LocationUpdateLogEvent = { message?: string; }; -export type LocationSpec = { - type: string; - target: string; -}; - -export type Location = { - id: string; -} & LocationSpec; - export type LocationResponse = { data: Location; currentStatus: LocationUpdateStatus; diff --git a/plugins/catalog-backend/src/database/CommonDatabase.test.ts b/plugins/catalog-backend/src/database/CommonDatabase.test.ts index 8f62969bd1..f1723e3733 100644 --- a/plugins/catalog-backend/src/database/CommonDatabase.test.ts +++ b/plugins/catalog-backend/src/database/CommonDatabase.test.ts @@ -19,10 +19,9 @@ import { getVoidLogger, NotFoundError, } from '@backstage/backend-common'; -import type { Entity } from '@backstage/catalog-model'; +import type { Entity, Location } from '@backstage/catalog-model'; import Knex from 'knex'; import path from 'path'; -import { Location } from '../catalog'; import { CommonDatabase } from './CommonDatabase'; import { DatabaseLocationUpdateLogStatus } from './types'; import type { diff --git a/plugins/catalog-backend/src/database/CommonDatabase.ts b/plugins/catalog-backend/src/database/CommonDatabase.ts index 084f6ea662..dd965c89ef 100644 --- a/plugins/catalog-backend/src/database/CommonDatabase.ts +++ b/plugins/catalog-backend/src/database/CommonDatabase.ts @@ -19,7 +19,7 @@ import { InputError, NotFoundError, } from '@backstage/backend-common'; -import type { Entity, EntityMeta } from '@backstage/catalog-model'; +import type { Entity, EntityMeta, Location } from '@backstage/catalog-model'; import Knex from 'knex'; import lodash from 'lodash'; import { v4 as uuidv4 } from 'uuid'; @@ -37,7 +37,6 @@ import type { DbLocationsRowWithStatus, EntityFilters, } from './types'; -import { Location } from '../catalog'; function getStrippedMetadata(metadata: EntityMeta): EntityMeta { const output = lodash.cloneDeep(metadata); diff --git a/plugins/catalog-backend/src/database/types.ts b/plugins/catalog-backend/src/database/types.ts index 4bcc66af1c..17da373ae9 100644 --- a/plugins/catalog-backend/src/database/types.ts +++ b/plugins/catalog-backend/src/database/types.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import type { Entity } from '@backstage/catalog-model'; -import { Location } from '../catalog'; +import type { Entity, Location } from '@backstage/catalog-model'; export type DbEntitiesRow = { id: string; diff --git a/plugins/catalog-backend/src/ingestion/HigherOrderOperations.test.ts b/plugins/catalog-backend/src/ingestion/HigherOrderOperations.test.ts new file mode 100644 index 0000000000..7f1e890fbf --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/HigherOrderOperations.test.ts @@ -0,0 +1,143 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntitiesCatalog, LocationsCatalog } from '../catalog'; +import { IngestionModel } from './types'; +import { HigherOrderOperations } from './HigherOrderOperations'; +import { Entity } from '@backstage/catalog-model'; + +describe('HigherOrderOperations', () => { + let entitiesCatalog: jest.Mocked; + let locationsCatalog: jest.Mocked; + let ingestionModel: jest.Mocked; + let higherOrderOperation: HigherOrderOperations; + + beforeAll(() => { + entitiesCatalog = { + entities: jest.fn(), + entityByUid: jest.fn(), + entityByName: jest.fn(), + addOrUpdateEntity: jest.fn(), + removeEntityByUid: jest.fn(), + }; + locationsCatalog = { + addLocation: jest.fn(), + removeLocation: jest.fn(), + locations: jest.fn(), + location: jest.fn(), + locationHistory: jest.fn(), + }; + ingestionModel = { + readLocation: jest.fn(), + }; + higherOrderOperation = new HigherOrderOperations( + entitiesCatalog, + locationsCatalog, + ingestionModel, + ); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('addLocation', () => { + it('just inserts the location when there are no entities to read', async () => { + const spec = { + type: 'a', + target: 'b', + }; + locationsCatalog.addLocation.mockImplementation(x => Promise.resolve(x)); + locationsCatalog.locations.mockResolvedValue([]); + ingestionModel.readLocation.mockResolvedValue([]); + + const result = await higherOrderOperation.addLocation(spec); + + expect(result.location).toEqual( + expect.objectContaining({ + id: expect.anything(), + ...spec, + }), + ); + expect(result.entities).toEqual([]); + expect(locationsCatalog.locations).toBeCalledTimes(1); + expect(ingestionModel.readLocation).toBeCalledTimes(1); + expect(ingestionModel.readLocation).toBeCalledWith('a', 'b'); + expect(entitiesCatalog.addOrUpdateEntity).not.toBeCalled(); + expect(locationsCatalog.addLocation).toBeCalledTimes(1); + expect(locationsCatalog.addLocation).toBeCalledWith( + expect.objectContaining({ + id: expect.anything(), + ...spec, + }), + ); + }); + + it('reuses the location if a match already existed', async () => { + const spec = { + type: 'a', + target: 'b', + }; + const location = { + id: 'dd12620d-0436-422f-93bd-929aa0788123', + ...spec, + }; + + locationsCatalog.locations.mockResolvedValue([ + { + currentStatus: { timestamp: '', status: '', message: '' }, + data: location, + }, + ]); + ingestionModel.readLocation.mockResolvedValue([]); + + const result = await higherOrderOperation.addLocation(spec); + + expect(result.location).toEqual(location); + expect(result.entities).toEqual([]); + expect(locationsCatalog.locations).toBeCalledTimes(1); + expect(ingestionModel.readLocation).toBeCalledTimes(1); + expect(ingestionModel.readLocation).toBeCalledWith('a', 'b'); + expect(entitiesCatalog.addOrUpdateEntity).not.toBeCalled(); + expect(locationsCatalog.addLocation).not.toBeCalled(); + }); + + it('rejects the whole operation if any entity could not be read', async () => { + const spec = { + type: 'a', + target: 'b', + }; + const entity: Entity = { + apiVersion: 'a', + kind: 'b', + metadata: { name: 'n' }, + }; + + locationsCatalog.locations.mockResolvedValue([]); + ingestionModel.readLocation.mockResolvedValue([ + { type: 'data', data: entity }, + { type: 'error', error: new Error('abcd') }, + ]); + + await expect(higherOrderOperation.addLocation(spec)).rejects.toThrow( + /abcd/, + ); + expect(locationsCatalog.locations).toBeCalledTimes(1); + expect(entitiesCatalog.addOrUpdateEntity).not.toBeCalled(); + expect(locationsCatalog.addLocation).not.toBeCalled(); + }); + }); +}); diff --git a/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts b/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts index 0314556e27..e28d1e722a 100644 --- a/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts +++ b/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts @@ -15,14 +15,9 @@ */ import { InputError } from '@backstage/backend-common'; -import { Entity } from '@backstage/catalog-model'; +import { Entity, Location, LocationSpec } from '@backstage/catalog-model'; import { v4 as uuidv4 } from 'uuid'; -import { - EntitiesCatalog, - Location, - LocationsCatalog, - LocationSpec, -} from '../catalog'; +import { EntitiesCatalog, LocationsCatalog } from '../catalog'; import { IngestionModel } from '../ingestion'; import { AddLocationResult, HigherOrderOperation } from './types'; diff --git a/plugins/catalog-backend/src/ingestion/types.ts b/plugins/catalog-backend/src/ingestion/types.ts index 45dd0d9f74..018784bd0f 100644 --- a/plugins/catalog-backend/src/ingestion/types.ts +++ b/plugins/catalog-backend/src/ingestion/types.ts @@ -14,9 +14,8 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; -import { Location, LocationSpec } from '../catalog'; -import { ReaderOutput } from './descriptor/parsers/types'; +import type { Entity, Location, LocationSpec } from '@backstage/catalog-model'; +import type { ReaderOutput } from './descriptor/parsers/types'; export type AddLocationResult = { location: Location; diff --git a/plugins/catalog-backend/src/service/router.test.ts b/plugins/catalog-backend/src/service/router.test.ts index e03cb3dc98..d26476bca0 100644 --- a/plugins/catalog-backend/src/service/router.test.ts +++ b/plugins/catalog-backend/src/service/router.test.ts @@ -15,10 +15,10 @@ */ import { getVoidLogger, NotFoundError } from '@backstage/backend-common'; -import type { Entity } from '@backstage/catalog-model'; +import type { Entity, LocationSpec } from '@backstage/catalog-model'; import express from 'express'; import request from 'supertest'; -import { EntitiesCatalog, LocationsCatalog, LocationSpec } from '../catalog'; +import { EntitiesCatalog, LocationsCatalog } from '../catalog'; import { LocationResponse } from '../catalog/types'; import { HigherOrderOperation } from '../ingestion/types'; import { createRouter } from './router'; @@ -29,7 +29,7 @@ describe('createRouter', () => { let higherOrderOperation: jest.Mocked; let app: express.Express; - beforeEach(async () => { + beforeAll(async () => { entitiesCatalog = { entities: jest.fn(), entityByUid: jest.fn(), @@ -56,6 +56,10 @@ describe('createRouter', () => { app = express().use(router); }); + beforeEach(() => { + jest.resetAllMocks(); + }); + describe('GET /entities', () => { it('happy path: lists entities', async () => { const entities: Entity[] = [ diff --git a/plugins/catalog-backend/src/service/router.ts b/plugins/catalog-backend/src/service/router.ts index 95ea068f58..22d1f73730 100644 --- a/plugins/catalog-backend/src/service/router.ts +++ b/plugins/catalog-backend/src/service/router.ts @@ -15,12 +15,12 @@ */ import { errorHandler, InputError } from '@backstage/backend-common'; -import { Entity } from '@backstage/catalog-model'; +import { locationSpecSchema } from '@backstage/catalog-model'; +import type { Entity } from '@backstage/catalog-model'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; -import * as yup from 'yup'; -import { EntitiesCatalog, LocationsCatalog, LocationSpec } from '../catalog'; +import { EntitiesCatalog, LocationsCatalog } from '../catalog'; import { EntityFilters } from '../database'; import { HigherOrderOperation } from '../ingestion/types'; import { requireRequestBody, validateRequestBody } from './util'; @@ -32,13 +32,6 @@ export interface RouterOptions { logger: Logger; } -const addLocationSchema = yup - .object({ - type: yup.string().required(), - target: yup.string().required(), - }) - .noUnknown(); - export async function createRouter( options: RouterOptions, ): Promise { @@ -92,7 +85,7 @@ export async function createRouter( if (higherOrderOperation) { router.post('/locations', async (req, res) => { - const input = await validateRequestBody(req, addLocationSchema); + const input = await validateRequestBody(req, locationSpecSchema); const output = await higherOrderOperation.addLocation(input); res.status(201).send(output); });