diff --git a/frontend/package.json b/frontend/package.json index 34d6a4c2cc9c..4e26cdde5c7c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -130,6 +130,7 @@ "@typescript-eslint/parser": "^1.7.0", "bootstrap-sass": "^3.3.7", "cache-loader": "1.x", + "chalk": "2.3.x", "chromedriver": "^2.43.3", "circular-dependency-plugin": "5.0.2", "css-loader": "0.28.x", diff --git a/frontend/packages/console-demo-plugin/src/plugin.ts b/frontend/packages/console-demo-plugin/src/plugin.ts index af64ab9eddba..f800a35d471b 100644 --- a/frontend/packages/console-demo-plugin/src/plugin.ts +++ b/frontend/packages/console-demo-plugin/src/plugin.ts @@ -4,6 +4,7 @@ import { ResourceNSNavItem, ResourceListPage, ResourceDetailPage, + ModelBasedFeatureFlag, } from '@console/plugin-sdk'; // TODO(vojtech): internal code needed by plugins should be moved to console-shared package @@ -13,7 +14,8 @@ type ConsumedExtensions = | HrefNavItem | ResourceNSNavItem | ResourceListPage - | ResourceDetailPage; + | ResourceDetailPage + | ModelBasedFeatureFlag; const plugin: Plugin = [ { @@ -50,6 +52,13 @@ const plugin: Plugin = [ loader: () => import('@console/internal/components/pod' /* webpackChunkName: "pod" */).then(m => m.PodsDetailsPage), }, }, + { + type: 'FeatureFlag/ModelBased', + properties: { + model: PodModel, + flag: 'TEST_MODEL_FLAG', + }, + }, ]; export default plugin; diff --git a/frontend/packages/console-plugin-sdk/src/codegen/__tests__/index.spec.ts b/frontend/packages/console-plugin-sdk/src/codegen/__tests__/index.spec.ts new file mode 100644 index 000000000000..48ad53b794b7 --- /dev/null +++ b/frontend/packages/console-plugin-sdk/src/codegen/__tests__/index.spec.ts @@ -0,0 +1,104 @@ +import { + Package, + PluginPackage, + isValidPluginPackage, + resolveActivePlugins, + getActivePluginsModule, +} from '..'; + +const templatePackage: Package = { name: 'test', version: '1.2.3', readme: '', _id: '@' }; + +describe('codegen', () => { + + describe('isValidPluginPackage', () => { + it('returns false if package.consolePlugin is missing', () => { + expect(isValidPluginPackage({ + ...templatePackage, + })).toBe(false); + }); + + it('returns false if package.consolePlugin.entry is missing', () => { + expect(isValidPluginPackage({ + ...templatePackage, + consolePlugin: {}, + })).toBe(false); + }); + + it('returns false if package.consolePlugin.entry is an empty string', () => { + expect(isValidPluginPackage({ + ...templatePackage, + consolePlugin: { entry: '' }, + })).toBe(false); + }); + + it('returns true if package.consolePlugin.entry is not an empty string', () => { + expect(isValidPluginPackage({ + ...templatePackage, + consolePlugin: { entry: 'plugin.ts' }, + })).toBe(true); + }); + }); + + describe('resolveActivePlugins', () => { + it('filters out packages which are not listed in appPackage.dependencies', () => { + const appPackage: Package = { + ...templatePackage, + name: 'app', + dependencies: { + 'foo': '0.1.2', + 'bar': '1.2.3', + }, + }; + + const pluginPackages: PluginPackage[] = [ + { + ...templatePackage, + name: 'bar', + version: '1.2.3', + consolePlugin: { entry: 'plugin.ts' }, + }, + { + ...templatePackage, + name: 'qux', + version: '2.3.4', + consolePlugin: { entry: 'plugin.ts' }, + }, + ]; + + expect(resolveActivePlugins(appPackage, pluginPackages)).toEqual([ + { ...pluginPackages[0] }, + ]); + }); + }); + + describe('getActivePluginsModule', () => { + it('returns the source of a module that exports the list of active plugins', () => { + const pluginPackages: PluginPackage[] = [ + { + ...templatePackage, + name: 'bar', + version: '1.2.3', + consolePlugin: { entry: 'src/plugin.ts' }, + }, + { + ...templatePackage, + name: 'qux-plugin', + version: '2.3.4', + consolePlugin: { entry: 'index.ts' }, + }, + ]; + + const expectedModule = ` + const activePlugins = []; + import plugin_0 from 'bar/src/plugin.ts'; + activePlugins.push(plugin_0); + import plugin_1 from 'qux-plugin/index.ts'; + activePlugins.push(plugin_1); + export default activePlugins; + `.replace(/^\s+/gm, ''); + + expect(getActivePluginsModule(pluginPackages)).toBe(expectedModule); + }); + }); + +}); diff --git a/frontend/packages/console-plugin-sdk/src/codegen/index.ts b/frontend/packages/console-plugin-sdk/src/codegen/index.ts index c16615c0d65f..b08bdf078720 100644 --- a/frontend/packages/console-plugin-sdk/src/codegen/index.ts +++ b/frontend/packages/console-plugin-sdk/src/codegen/index.ts @@ -3,19 +3,29 @@ import * as path from 'path'; import * as readPkg from 'read-pkg'; -type Package = readPkg.NormalizedPackageJson; +export type Package = readPkg.NormalizedPackageJson; -interface PluginPackage extends Package { +export interface PluginPackage extends Package { consolePlugin: { entry: string; } } -function isValidPluginPackage(pkg: Package): pkg is PluginPackage { - return (pkg as PluginPackage).consolePlugin && typeof (pkg as PluginPackage).consolePlugin.entry === 'string'; +export function isValidPluginPackage(pkg: Package): pkg is PluginPackage { + if (!(pkg as PluginPackage).consolePlugin) { + return false; + } + + const entry = (pkg as PluginPackage).consolePlugin.entry; + return typeof entry === 'string' && entry.length > 0; } -function readPackages(packageFiles: string[]) { +/** + * Read package metadata and detect any plugins. + * + * @param packageFiles Paths to `package.json` files (all the monorepo packages). + */ +export function readPackages(packageFiles: string[]) { const pkgList: Package[] = packageFiles.map(file => readPkg.sync({ cwd: path.dirname(file), normalize: true })); return { @@ -24,32 +34,29 @@ function readPackages(packageFiles: string[]) { }; } +/** + * Resolve the list of active plugins. + */ +export function resolveActivePlugins(appPackage: Package, pluginPackages: PluginPackage[]) { + return pluginPackages.filter(pkg => appPackage.dependencies[pkg.name] === pkg.version); +} + /** * Generate the "active plugins" module source. - * - * @param packageFiles Paths to `package.json` files (all the monorepo packages). */ -export function getActivePluginsModule(packageFiles: string[]): string { - const { appPackage, pluginPackages } = readPackages(packageFiles); +export function getActivePluginsModule(activePluginPackages: PluginPackage[]): string { let output = ` const activePlugins = []; `; - if (appPackage) { - for (const depName of Object.keys(appPackage.dependencies)) { - const depVersion = appPackage.dependencies[depName]; - const foundPluginPackage = pluginPackages.find(pkg => pkg.name === depName && pkg.version === depVersion); - - if (foundPluginPackage) { - const importName = `plugin_${pluginPackages.indexOf(foundPluginPackage)}`; - const importPath = `${foundPluginPackage.name}/${foundPluginPackage.consolePlugin.entry}`; - output = ` - ${output} - import ${importName} from '${importPath}'; - activePlugins.push(${importName}); - `; - } - } + for (const pkg of activePluginPackages) { + const importName = `plugin_${activePluginPackages.indexOf(pkg)}`; + const importPath = `${pkg.name}/${pkg.consolePlugin.entry}`; + output = ` + ${output} + import ${importName} from '${importPath}'; + activePlugins.push(${importName}); + `; } output = ` diff --git a/frontend/packages/console-plugin-sdk/src/registry.ts b/frontend/packages/console-plugin-sdk/src/registry.ts index 1e312044ba87..a8e609be763e 100644 --- a/frontend/packages/console-plugin-sdk/src/registry.ts +++ b/frontend/packages/console-plugin-sdk/src/registry.ts @@ -1,5 +1,5 @@ import * as _ from 'lodash-es'; -import { Extension, PluginList, isNavItem, isResourcePage } from './typings'; +import { Extension, PluginList, isNavItem, isResourcePage, isFeatureFlag } from './typings'; /** * Registry used to query for Console extensions. @@ -20,4 +20,8 @@ export class ExtensionRegistry { return this.extensions.filter(isResourcePage); } + public getFeatureFlags() { + return this.extensions.filter(isFeatureFlag); + } + } diff --git a/frontend/packages/console-plugin-sdk/src/typings/features.ts b/frontend/packages/console-plugin-sdk/src/typings/features.ts new file mode 100644 index 000000000000..22b91651ed6c --- /dev/null +++ b/frontend/packages/console-plugin-sdk/src/typings/features.ts @@ -0,0 +1,24 @@ +import { Extension } from '.'; +import { K8sKind } from '@console/internal/module/k8s'; + +namespace ExtensionProperties { + export interface ModelBasedFeatureFlag { + model: K8sKind; + flag: string; + } +} + +export interface ModelBasedFeatureFlag extends Extension { + type: 'FeatureFlag/ModelBased'; +} + +// TODO(vojtech): add ActionBasedFeatureFlag +export type FeatureFlag = ModelBasedFeatureFlag; + +export function isModelBasedFeatureFlag(e: Extension): e is ModelBasedFeatureFlag { + return e.type === 'FeatureFlag/ModelBased'; +} + +export function isFeatureFlag(e: Extension): e is FeatureFlag { + return isModelBasedFeatureFlag(e); +} diff --git a/frontend/packages/console-plugin-sdk/src/typings/index.ts b/frontend/packages/console-plugin-sdk/src/typings/index.ts index 87dc142a710b..4619ab416cc5 100644 --- a/frontend/packages/console-plugin-sdk/src/typings/index.ts +++ b/frontend/packages/console-plugin-sdk/src/typings/index.ts @@ -62,5 +62,6 @@ export type PluginList = Plugin>[]; // TODO(vojtech): internal code needed by plugin SDK should be moved to console-shared package +export * from './features'; export * from './nav'; export * from './pages'; diff --git a/frontend/packages/console-plugin-sdk/src/typings/nav.ts b/frontend/packages/console-plugin-sdk/src/typings/nav.ts index ef7943335330..b8ea5267ad69 100644 --- a/frontend/packages/console-plugin-sdk/src/typings/nav.ts +++ b/frontend/packages/console-plugin-sdk/src/typings/nav.ts @@ -1,36 +1,38 @@ import { Extension } from '.'; import { K8sKind } from '@console/internal/module/k8s'; -export interface NavItemProperties { - // TODO(vojtech): link to existing nav sections by value - section: 'Home' | 'Workloads'; - componentProps: { - name: string; - required?: string; - disallowed?: string; - startsWith?: string[]; +namespace ExtensionProperties { + interface NavItem { + // TODO(vojtech): link to existing nav sections by value + section: 'Home' | 'Workloads'; + componentProps: { + name: string; + required?: string; + disallowed?: string; + startsWith?: string[]; + } } -} -export interface HrefProperties extends NavItemProperties { - componentProps: NavItemProperties['componentProps'] & { - href: string; - activePath?: string; + export interface HrefNavItem extends NavItem { + componentProps: NavItem['componentProps'] & { + href: string; + activePath?: string; + } } -} -export interface ResourceNSProperties extends NavItemProperties { - componentProps: NavItemProperties['componentProps'] & { - resource: string; - model?: K8sKind; + export interface ResourceNSNavItem extends NavItem { + componentProps: NavItem['componentProps'] & { + resource: string; + model?: K8sKind; + } } } -export interface HrefNavItem extends Extension { +export interface HrefNavItem extends Extension { type: 'NavItem/Href'; } -export interface ResourceNSNavItem extends Extension { +export interface ResourceNSNavItem extends Extension { type: 'NavItem/ResourceNS'; } diff --git a/frontend/packages/console-plugin-sdk/src/typings/pages.ts b/frontend/packages/console-plugin-sdk/src/typings/pages.ts index 05f5945aa3ea..27d283915fa9 100644 --- a/frontend/packages/console-plugin-sdk/src/typings/pages.ts +++ b/frontend/packages/console-plugin-sdk/src/typings/pages.ts @@ -2,16 +2,18 @@ import * as React from 'react'; import { Extension } from '.'; import { K8sKind } from '@console/internal/module/k8s'; -export interface ResourcePageProperties { - model: K8sKind; - loader: () => Promise>; +namespace ExtensionProperties { + export interface ResourcePage { + model: K8sKind; + loader: () => Promise>; + } } -export interface ResourceListPage extends Extension { +export interface ResourceListPage extends Extension { type: 'ResourcePage/List'; } -export interface ResourceDetailPage extends Extension { +export interface ResourceDetailPage extends Extension { type: 'ResourcePage/Detail'; } diff --git a/frontend/public/components/app.jsx b/frontend/public/components/app.jsx index 027349f10c7e..4356e2e95c2e 100644 --- a/frontend/public/components/app.jsx +++ b/frontend/public/components/app.jsx @@ -349,6 +349,7 @@ window.onunhandledrejection = function(e) { if ('serviceWorker' in navigator) { if (window.SERVER_FLAGS.loadTestFactor > 1) { + // eslint-disable-next-line import/no-unresolved import('file-loader?name=load-test.sw.js!../load-test.sw.js') .then(() => navigator.serviceWorker.register('/load-test.sw.js')) .then(() => new Promise(r => navigator.serviceWorker.controller ? r() : navigator.serviceWorker.addEventListener('controllerchange', () => r()))) diff --git a/frontend/public/features.ts b/frontend/public/features.ts index 218c83bdbe58..6f7fd46cc959 100644 --- a/frontend/public/features.ts +++ b/frontend/public/features.ts @@ -22,6 +22,7 @@ import { types } from './module/k8s/k8s-actions'; import { coFetchJSON } from './co-fetch'; import { MonitoringRoutes, setMonitoringURL } from './monitoring'; import { UIActions } from './ui/ui-actions'; +import * as plugins from './plugins'; export enum FLAGS { AUTH_ENABLED = 'AUTH_ENABLED', @@ -62,6 +63,16 @@ export const CRDs = { [referenceForModel(MachineConfigModel)]: FLAGS.MACHINE_CONFIG, }; +plugins.registry.getFeatureFlags().forEach(ff => { + const modelRef = referenceForModel(ff.properties.model); + if (!CRDs[modelRef]) { + CRDs[modelRef] = ff.properties.flag as FLAGS; + } else { + // eslint-disable-next-line no-console + console.warn(`attempt to redefine flag for model ${modelRef}`); + } +}); + const SET_FLAG = 'SET_FLAG'; export const setFlag = (dispatch, flag, value) => dispatch({flag, value, type: SET_FLAG}); diff --git a/frontend/public/plugins.ts b/frontend/public/plugins.ts index a2e71bb689ef..1a33c323d01e 100644 --- a/frontend/public/plugins.ts +++ b/frontend/public/plugins.ts @@ -10,5 +10,7 @@ const activePlugins = (process.env.NODE_ENV !== 'test') export const registry = new ExtensionRegistry(activePlugins); -// eslint-disable-next-line no-console -console.info(`${activePlugins.length} plugins active`); +if (process.env.NODE_ENV !== 'test') { + // eslint-disable-next-line no-console + console.info(`${activePlugins.length} plugins active`); +} diff --git a/frontend/webpack.config.ts b/frontend/webpack.config.ts index 3821565e2579..148e4d8879e1 100644 --- a/frontend/webpack.config.ts +++ b/frontend/webpack.config.ts @@ -4,17 +4,18 @@ import * as webpack from 'webpack'; import * as path from 'path'; import * as glob from 'glob'; +import { default as chalk } from 'chalk'; import * as HtmlWebpackPlugin from 'html-webpack-plugin'; import * as ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import * as MiniCssExtractPlugin from 'mini-css-extract-plugin'; import * as VirtualModulesPlugin from 'webpack-virtual-modules'; -import { getActivePluginsModule } from '@console/plugin-sdk/src/codegen'; + +import { readPackages, resolveActivePlugins, getActivePluginsModule } from '@console/plugin-sdk/src/codegen'; const NODE_ENV = process.env.NODE_ENV; /* Helpers */ const extractCSS = new MiniCssExtractPlugin({filename: 'app-bundle.css'}); -const packageFiles = glob.sync('packages/*/package.json', { absolute: true }); const config: webpack.Configuration = { entry: ['./polyfills.js', '@console/app'], @@ -117,10 +118,6 @@ const config: webpack.Configuration = { chunksSortMode: 'none', }), extractCSS, - // Generate '@console/active-plugins' module - new VirtualModulesPlugin({ - 'node_modules/@console/active-plugins.js': getActivePluginsModule(packageFiles), - }), ], devtool: 'cheap-module-source-map', stats: 'minimal', @@ -136,4 +133,18 @@ if (NODE_ENV === 'production') { config.stats = 'normal'; } +/* Console plugin support */ +const packageFiles = glob.sync('packages/*/package.json', { absolute: true }); +const { appPackage, pluginPackages } = readPackages(packageFiles); +const activePluginPackages = appPackage ? resolveActivePlugins(appPackage, pluginPackages) : []; + +config.plugins.push( + new VirtualModulesPlugin({ + 'node_modules/@console/active-plugins.js': getActivePluginsModule(activePluginPackages), + }), +); + +// eslint-disable-next-line no-console +console.log(`Active plugins: [${(activePluginPackages.map(pkg => `${chalk.green(pkg.name)}`).join(', '))}]`); + export default config; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index a11c9249178f..0d710e75afe0 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2069,6 +2069,7 @@ balanced-match@^0.4.2: balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= barycentric@^1.0.1: version "1.0.1" @@ -2278,6 +2279,7 @@ box-intersect@^1.0.1: brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -2448,9 +2450,10 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -builtin-modules@^1.0.0, builtin-modules@^1.1.1: +builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= builtin-status-codes@^3.0.0: version "3.0.0" @@ -2617,6 +2620,14 @@ chain-function@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" +chalk@2.3.x, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -2627,14 +2638,6 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - chalk@^2.3.0: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" @@ -3121,6 +3124,7 @@ compute-dims@^1.1.0: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@~1.6.0: version "1.6.2" @@ -3156,6 +3160,7 @@ constants-browserify@^1.0.0: contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= content-disposition@0.5.2: version "0.5.2" @@ -3740,6 +3745,7 @@ dateformat@^3.0.2: debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" @@ -3941,6 +3947,7 @@ dnd-core@^2.6.0: doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= dependencies: esutils "^2.0.2" isarray "^1.0.0" @@ -4277,7 +4284,14 @@ errno@^0.1.3, errno@~0.1.7: dependencies: prr "~1.0.1" -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error-ex@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: @@ -4433,34 +4447,38 @@ escodegen@~1.3.2: optionalDependencies: source-map "~0.1.33" -eslint-import-resolver-node@^0.3.1: +eslint-import-resolver-node@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== dependencies: debug "^2.6.9" resolve "^1.5.0" -eslint-module-utils@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" +eslint-module-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a" + integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw== dependencies: debug "^2.6.8" - pkg-dir "^1.0.0" + pkg-dir "^2.0.0" eslint-plugin-import@2.x: - version "2.9.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169" + version "2.17.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.2.tgz#d227d5c6dc67eca71eb590d2bb62fb38d86e9fcb" + integrity sha512-m+cSVxM7oLsIpmwNn2WXTJoReOF9f/CtLMo7qOVmKd1KntBy0hEcuNZ3erTmWjx+DxRO0Zcrm5KwAvI9wHcV5g== dependencies: - builtin-modules "^1.1.1" + array-includes "^3.0.3" contains-path "^0.1.0" - debug "^2.6.8" + debug "^2.6.9" doctrine "1.5.0" - eslint-import-resolver-node "^0.3.1" - eslint-module-utils "^2.1.1" - has "^1.0.1" - lodash "^4.17.4" - minimatch "^3.0.3" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.4.0" + has "^1.0.3" + lodash "^4.17.11" + minimatch "^3.0.4" read-pkg-up "^2.0.0" + resolve "^1.10.0" eslint-plugin-react-hooks@^1.6.0: version "1.6.0" @@ -4604,6 +4622,7 @@ estraverse@~1.5.0: esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= esutils@~1.0.0: version "1.0.0" @@ -5009,6 +5028,7 @@ find-root@^1.1.0: find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -6081,11 +6101,11 @@ got@^8.2.0: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -graceful-fs@^4.1.15: +graceful-fs@^4.1.15, graceful-fs@^4.1.2: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== @@ -6256,6 +6276,7 @@ has@^1.0.0, has@~1.0.1: has@^1.0.1, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" @@ -6347,8 +6368,9 @@ homedir-polyfill@^1.0.1: parse-passwd "^1.0.0" hosted-git-info@^2.1.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== hsluv@^0.0.3: version "0.0.3" @@ -6709,6 +6731,7 @@ is-accessor-descriptor@^1.0.0: is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-base64@^0.1.0: version "0.1.0" @@ -6747,6 +6770,7 @@ is-buffer@^2.0.3: is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= dependencies: builtin-modules "^1.0.0" @@ -7820,6 +7844,7 @@ load-json-file@^1.0.0: load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -7859,6 +7884,7 @@ loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -8568,6 +8594,7 @@ move-concurrently@^1.0.1: ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@^2.1.1: version "2.1.1" @@ -8908,22 +8935,22 @@ nopt@~1.0.10: dependencies: abbrev "1" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" + resolve "^1.10.0" semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== +normalize-package-data@^2.3.4: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: hosted-git-info "^2.1.4" - resolve "^1.10.0" + is-builtin-module "^1.0.0" semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" @@ -9300,8 +9327,9 @@ p-lazy@^1.0.0: resolved "https://registry.yarnpkg.com/p-lazy/-/p-lazy-1.0.0.tgz#ec53c802f2ee3ac28f166cc82d0b2b02de27a835" p-limit@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" @@ -9315,6 +9343,7 @@ p-limit@^2.0.0: p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" @@ -9348,6 +9377,7 @@ p-timeout@^2.0.1: p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= p-try@^2.0.0: version "2.0.0" @@ -9411,6 +9441,7 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= dependencies: error-ex "^1.2.0" @@ -9472,12 +9503,14 @@ path-dirname@^1.0.0: path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" @@ -9491,11 +9524,7 @@ path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - -path-parse@^1.0.6: +path-parse@^1.0.5, path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== @@ -9521,6 +9550,7 @@ path-type@^1.0.0: path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= dependencies: pify "^2.0.0" @@ -9691,6 +9721,7 @@ pick-by-alias@^1.1.0, pick-by-alias@^1.1.1, pick-by-alias@^1.2.0: pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= pify@^3.0.0: version "3.0.0" @@ -9704,18 +9735,14 @@ pify@^4.0.1: pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - dependencies: - find-up "^1.0.0" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= pkg-dir@^2.0.0: version "2.0.0" @@ -10797,6 +10824,7 @@ read-pkg-up@^1.0.1: read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= dependencies: find-up "^2.0.0" read-pkg "^2.0.0" @@ -10829,6 +10857,7 @@ read-pkg@^1.0.0: read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= dependencies: load-json-file "^2.0.0" normalize-package-data "^2.3.2" @@ -11445,13 +11474,13 @@ resolve@^0.6.1: version "0.6.3" resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.6.3.tgz#dd957982e7e736debdf53b58a4dd91754575dd46" -resolve@^1.0.0, resolve@^1.1.5, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.5.0, resolve@~1.5.0: +resolve@^1.0.0, resolve@^1.1.5, resolve@^1.1.6, resolve@^1.1.7, resolve@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" -resolve@^1.10.0: +resolve@^1.10.0, resolve@^1.5.0: version "1.10.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.1.tgz#664842ac960795bbe758221cdccda61fb64b5f18" integrity sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA== @@ -11784,7 +11813,12 @@ selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: tmp "0.0.30" xml2js "^0.4.17" -"semver@2 || 3 || 4 || 5", semver@5.5.0, semver@^5.0.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: +"semver@2 || 3 || 4 || 5": + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +semver@5.5.0, semver@^5.0.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" @@ -12175,26 +12209,30 @@ sourcemap-codec@^1.4.1: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== spdx-expression-parse@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + version "3.0.4" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" + integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== split-polygon@^1.0.0: version "1.0.0" @@ -13408,8 +13446,9 @@ v8-compile-cache@^1.1.2: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0"