diff --git a/.eslintignore b/.eslintignore index 9a0d3d6a09752..f1448bf91ba03 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,6 +6,7 @@ bower_components /plugins /optimize /built_assets +/html_docs /src/fixtures/vislib/mock_data /src/legacy/ui/public/angular-bootstrap /src/legacy/ui/public/flot-charts diff --git a/.eslintrc.js b/.eslintrc.js index 3d5be9fa46501..ea7490c59ee2e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -208,7 +208,7 @@ module.exports = { */ { files: [ - 'test/functional/services/lib/leadfoot_element_wrapper/scroll_into_view_if_necessary.js', + 'test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js', '**/browser_exec_scripts/**/*', ], rules: { diff --git a/.i18nrc.json b/.i18nrc.json index c36dcf6b6abc4..4e942485d3aab 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -40,18 +40,14 @@ "xpack.rollupJobs": "x-pack/plugins/rollup", "xpack.searchProfiler": "x-pack/plugins/searchprofiler", "xpack.security": "x-pack/plugins/security", + "xpack.server": "x-pack/server", "xpack.spaces": "x-pack/plugins/spaces", "xpack.upgradeAssistant": "x-pack/plugins/upgrade_assistant", "xpack.uptime": "x-pack/plugins/uptime", "xpack.watcher": "x-pack/plugins/watcher" }, "exclude": [ - "src/legacy/ui/ui_render/bootstrap/app_bootstrap.js", - "src/legacy/ui/ui_render/ui_render_mixin.js", - "x-pack/plugins/infra/public/graphql/types.ts", - "x-pack/plugins/infra/public/utils/loading_state/loading_result.ts", - "x-pack/plugins/infra/server/graphql/types.ts", - "x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts" + "src/legacy/ui/ui_render/ui_render_mixin.js" ], "translations": [ "x-pack/plugins/translations/translations/zh-CN.json" diff --git a/.node-version b/.node-version index 1047f696810da..95abd2ac49910 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -10.15.1 +10.15.2 diff --git a/.nvmrc b/.nvmrc index 1047f696810da..95abd2ac49910 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -10.15.1 +10.15.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5666ee755fe2..afe90683b61a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -295,6 +295,9 @@ ReactDOM.render( ); ``` +There is a number of tools was created to support internationalization in Kibana that would allow one to validate internationalized labels, +extract them to a `JSON` file or integrate translations back to Kibana. To know more, please read corresponding [readme](src/dev/i18n/README.md) file. + ### Testing and Building To ensure that your changes will not break other functionality, please run the test suite and build process before submitting your Pull Request. diff --git a/package.json b/package.json index 29a2da97b941e..482147d1e98ac 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "url": "https://github.com/elastic/kibana.git" }, "resolutions": { - "**/@types/node": "10.12.12" + "**/@types/node": "10.12.27" }, "workspaces": { "packages": [ @@ -246,8 +246,8 @@ "yauzl": "2.7.0" }, "devDependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "@elastic/eslint-config-kibana": "0.15.0", "@elastic/eslint-plugin-kibana-custom": "1.1.0", "@elastic/makelogs": "^4.4.0", @@ -281,7 +281,7 @@ "@types/has-ansi": "^3.0.0", "@types/hoek": "^4.1.3", "@types/humps": "^1.1.2", - "@types/jest": "^23.3.1", + "@types/jest": "^24.0.9", "@types/joi": "^13.4.2", "@types/jquery": "^3.3.6", "@types/js-yaml": "^3.11.1", @@ -292,7 +292,7 @@ "@types/mocha": "^5.2.6", "@types/moment-timezone": "^0.5.8", "@types/mustache": "^0.8.31", - "@types/node": "^10.12.12", + "@types/node": "^10.12.27", "@types/opn": "^5.1.0", "@types/podium": "^1.0.0", "@types/prop-types": "^15.5.3", @@ -359,8 +359,8 @@ "intl-messageformat-parser": "^1.4.0", "is-path-inside": "^2.0.0", "istanbul-instrumenter-loader": "3.0.1", - "jest": "^23.6.0", - "jest-cli": "^23.6.0", + "jest": "^24.1.0", + "jest-cli": "^24.1.0", "jest-raw-loader": "^1.0.1", "jimp": "0.2.28", "json-stable-stringify": "^1.0.1", @@ -373,7 +373,6 @@ "karma-junit-reporter": "1.2.0", "karma-mocha": "1.3.0", "karma-safari-launcher": "1.0.0", - "leadfoot": "1.7.5", "license-checker": "^16.0.0", "listr": "^0.14.1", "load-grunt-config": "0.19.2", @@ -392,6 +391,7 @@ "proxyquire": "1.7.11", "regenerate": "^1.4.0", "sass-lint": "^1.12.1", + "selenium-webdriver": "^4.0.0-alpha.1", "simple-git": "1.37.0", "sinon": "^5.0.7", "strip-ansi": "^3.0.1", @@ -401,19 +401,18 @@ "ts-jest": "^23.1.4", "ts-loader": "^5.2.2", "ts-node": "^7.0.1", - "tsconfig-paths": "^3.8.0", "tslint": "^5.11.0", "tslint-config-prettier": "^1.15.0", "tslint-microsoft-contrib": "^6.0.0", "tslint-plugin-prettier": "^2.0.0", - "typescript": "^3.0.3", + "typescript": "^3.3.3333", "vinyl-fs": "^3.0.2", "xml2js": "^0.4.19", "xmlbuilder": "9.0.4", "zlib": "^1.0.5" }, "engines": { - "node": "10.15.1", + "node": "10.15.2", "yarn": "^1.10.1" } } diff --git a/packages/eslint-config-kibana/.eslintrc.js b/packages/eslint-config-kibana/.eslintrc.js index 146f3df763dd0..5b72ce417200e 100644 --- a/packages/eslint-config-kibana/.eslintrc.js +++ b/packages/eslint-config-kibana/.eslintrc.js @@ -100,6 +100,7 @@ module.exports = { strict: [ 'error', 'never' ], 'valid-typeof': 'error', 'wrap-iife': [ 'error', 'outside' ], + 'eol-last': ['error', 'always'], yoda: 'off', 'object-curly-spacing': 'off', // overridden with babel/object-curly-spacing @@ -150,7 +151,7 @@ module.exports = { 'jsx-a11y/role-supports-aria-props': 'error', 'jsx-a11y/scope': 'error', 'jsx-a11y/tabindex-no-positive': 'error', - 'jsx-a11y/label-has-associated-control': 'error', + 'jsx-a11y/label-has-associated-control': 'error', 'react/jsx-equals-spacing': ['error', 'never'], 'react/jsx-indent': ['error', 2], 'react/no-will-update-set-state': 'error', diff --git a/packages/kbn-babel-code-parser/package.json b/packages/kbn-babel-code-parser/package.json index 7a9374e7216c9..23e7c29f22dfd 100755 --- a/packages/kbn-babel-code-parser/package.json +++ b/packages/kbn-babel-code-parser/package.json @@ -19,8 +19,8 @@ }, "dependencies": { "@kbn/babel-preset": "1.0.0", - "@babel/parser": "^7.1.3", - "@babel/traverse": "^7.1.4", + "@babel/parser": "^7.3.4", + "@babel/traverse": "^7.3.4", "lodash": "^4.17.11" } } diff --git a/src/legacy/core_plugins/interpreter/server/lib/feature_check.js b/packages/kbn-babel-preset/common_preset_7.js similarity index 50% rename from src/legacy/core_plugins/interpreter/server/lib/feature_check.js rename to packages/kbn-babel-preset/common_preset_7.js index 9f7a8993fa3ff..df72f382e2b0a 100644 --- a/src/legacy/core_plugins/interpreter/server/lib/feature_check.js +++ b/packages/kbn-babel-preset/common_preset_7.js @@ -17,10 +17,23 @@ * under the License. */ -// TODO: replace this when we use the method exposed by security https://github.com/elastic/kibana/pull/24616 -export const isSecurityEnabled = server => { - const kibanaSecurity = server.plugins.security; - const esSecurity = server.plugins.xpack_main.info.feature('security'); +module.exports = { + presets: [ + require.resolve('@babel/preset-react'), + require.resolve('@babel/preset-typescript'), + ], + plugins: [ + require.resolve('babel7-plugin-add-module-exports'), + // stage 3 + require.resolve('@babel/plugin-proposal-async-generator-functions'), + require.resolve('@babel/plugin-proposal-object-rest-spread'), - return kibanaSecurity && esSecurity.isAvailable() && esSecurity.isEnabled(); + // the class properties proposal was merged with the private fields proposal + // into the "class fields" proposal. Babel doesn't support this combined + // proposal yet, which includes private field, so this transform is + // TECHNICALLY stage 2, but for all intents and purposes it's stage 3 + // + // See https://github.com/babel/proposals/issues/12 for progress + require.resolve('@babel/plugin-proposal-class-properties'), + ], }; diff --git a/packages/kbn-babel-preset/node_preset_7.js b/packages/kbn-babel-preset/node_preset_7.js new file mode 100644 index 0000000000000..b57dd58dd9f15 --- /dev/null +++ b/packages/kbn-babel-preset/node_preset_7.js @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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. + */ + +module.exports = () => ({ + presets: [ + [ + require.resolve('@babel/preset-env'), + { + targets: { + // only applies the necessary transformations based on the + // current node.js processes version. For example: running + // `nvm install 8 && node ./src/cli` will run kibana in node + // version 8 and babel will stop transpiling async/await + // because they are supported in the "current" version of node + node: 'current', + }, + + // replaces `import "babel-polyfill"` with a list of require statements + // for just the polyfills that the target versions don't already supply + // on their own + useBuiltIns: 'entry', + }, + ], + require('./common_preset_7'), + ], + plugins: [ + [ + require.resolve('babel-plugin-transform-define'), + { + 'global.__BUILT_WITH_BABEL__': 'true' + } + ] + ] +}); diff --git a/packages/kbn-babel-preset/package.json b/packages/kbn-babel-preset/package.json index 1309d88197e5c..41c03c0542675 100644 --- a/packages/kbn-babel-preset/package.json +++ b/packages/kbn-babel-preset/package.json @@ -4,12 +4,20 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { + "@babel/core": "^7.3.4", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-class-properties": "^7.3.4", + "@babel/plugin-proposal-object-rest-spread": "^7.3.4", + "@babel/preset-env": "^7.3.4", + "@babel/preset-react": "^7.0.0", + "@babel/preset-typescript": "^7.3.3", "babel-plugin-add-module-exports": "^0.2.1", "babel-plugin-transform-async-generator-functions": "^6.24.1", "babel-plugin-transform-class-properties": "^6.24.1", - "babel-plugin-transform-define": "^1.3.0", + "babel-plugin-transform-define": "^1.3.1", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-preset-env": "^1.7.0", - "babel-preset-react": "^6.24.1" + "babel-preset-react": "^6.24.1", + "babel7-plugin-add-module-exports": "npm:babel-plugin-add-module-exports@^1.0.0" } } diff --git a/packages/kbn-config-schema/package.json b/packages/kbn-config-schema/package.json index 7b664a6e4a76b..2dd5b4615d91a 100644 --- a/packages/kbn-config-schema/package.json +++ b/packages/kbn-config-schema/package.json @@ -10,7 +10,7 @@ "kbn:bootstrap": "yarn build" }, "devDependencies": { - "typescript": "^3.0.3" + "typescript": "^3.3.3333" }, "peerDependencies": { "joi": "^13.5.2", diff --git a/packages/kbn-config-schema/src/duration/index.ts b/packages/kbn-config-schema/src/duration/index.ts index 58caa417a67ba..ff8f96614a193 100644 --- a/packages/kbn-config-schema/src/duration/index.ts +++ b/packages/kbn-config-schema/src/duration/index.ts @@ -48,7 +48,7 @@ function numberToDuration(numberMs: number) { return momentDuration(numberMs); } -export function ensureDuration(value?: Duration | string | number) { +export function ensureDuration(value: Duration | string | number) { if (typeof value === 'string') { return stringToDuration(value); } diff --git a/packages/kbn-config-schema/src/index.ts b/packages/kbn-config-schema/src/index.ts index 5ead81c0ddacf..ea155ef66c1d6 100644 --- a/packages/kbn-config-schema/src/index.ts +++ b/packages/kbn-config-schema/src/index.ts @@ -48,6 +48,8 @@ import { TypeOf, TypeOptions, UnionType, + URIOptions, + URIType, } from './types'; export { ObjectType, TypeOf, Type }; @@ -65,6 +67,10 @@ function string(options?: StringOptions): Type { return new StringType(options); } +function uri(options?: URIOptions): Type { + return new URIType(options); +} + function literal(value: T): Type { return new LiteralType(value); } @@ -188,6 +194,7 @@ export const schema = { recordOf, siblingRef, string, + uri, }; export type Schema = typeof schema; diff --git a/packages/kbn-config-schema/src/types/__snapshots__/uri_type.test.ts.snap b/packages/kbn-config-schema/src/types/__snapshots__/uri_type.test.ts.snap new file mode 100644 index 0000000000000..2836c80f5b5ad --- /dev/null +++ b/packages/kbn-config-schema/src/types/__snapshots__/uri_type.test.ts.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`#scheme returns error when shorter string 1`] = `"expected URI with scheme [http|https] but but got [ftp://elastic.co]."`; + +exports[`#scheme returns error when shorter string 2`] = `"expected URI with scheme [http|https] but but got [file:///kibana.log]."`; + +exports[`#validate throws when returns string 1`] = `"validator failure"`; + +exports[`is required by default 1`] = `"expected value of type [string] but got [undefined]."`; + +exports[`returns error when not string 1`] = `"expected value of type [string] but got [number]."`; + +exports[`returns error when not string 2`] = `"expected value of type [string] but got [Array]."`; + +exports[`returns error when not string 3`] = `"expected value of type [string] but got [RegExp]."`; + +exports[`returns error when value is not a URI 1`] = `"value is [3domain.local] but it must be a valid URI (see RFC 3986)."`; + +exports[`returns error when value is not a URI 2`] = `"value is [http://8010:0:0:0:9:500:300C:200A] but it must be a valid URI (see RFC 3986)."`; + +exports[`returns error when value is not a URI 3`] = `"value is [-] but it must be a valid URI (see RFC 3986)."`; + +exports[`returns error when value is not a URI 4`] = `"value is [https://example.com?baz[]=foo&baz[]=bar] but it must be a valid URI (see RFC 3986)."`; + +exports[`returns error when value is not a URI 5`] = `"value is [http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] but it must be a valid URI (see RFC 3986)."`; diff --git a/packages/kbn-config-schema/src/types/duration_type.test.ts b/packages/kbn-config-schema/src/types/duration_type.test.ts index 9a21afc6cf40f..39655d43d7b75 100644 --- a/packages/kbn-config-schema/src/types/duration_type.test.ts +++ b/packages/kbn-config-schema/src/types/duration_type.test.ts @@ -20,7 +20,7 @@ import { duration as momentDuration } from 'moment'; import { schema } from '..'; -const { duration } = schema; +const { duration, object, contextRef, siblingRef } = schema; test('returns value by default', () => { expect(duration().validate('123s')).toMatchSnapshot(); @@ -58,6 +58,70 @@ describe('#defaultValue', () => { }).validate(undefined) ).toMatchSnapshot(); }); + + test('can be a function that returns compatible type', () => { + expect( + duration({ + defaultValue: () => 600, + }).validate(undefined) + ).toMatchInlineSnapshot(`"PT0.6S"`); + + expect( + duration({ + defaultValue: () => '1h', + }).validate(undefined) + ).toMatchInlineSnapshot(`"PT1H"`); + + expect( + duration({ + defaultValue: () => momentDuration(1, 'hour'), + }).validate(undefined) + ).toMatchInlineSnapshot(`"PT1H"`); + }); + + test('can be a reference to a moment.Duration', () => { + expect( + object({ + source: duration({ defaultValue: 600 }), + target: duration({ defaultValue: siblingRef('source') }), + fromContext: duration({ defaultValue: contextRef('val') }), + }).validate(undefined, { val: momentDuration(700, 'ms') }) + ).toMatchInlineSnapshot(` +Object { + "fromContext": "PT0.7S", + "source": "PT0.6S", + "target": "PT0.6S", +} +`); + + expect( + object({ + source: duration({ defaultValue: '1h' }), + target: duration({ defaultValue: siblingRef('source') }), + fromContext: duration({ defaultValue: contextRef('val') }), + }).validate(undefined, { val: momentDuration(2, 'hour') }) + ).toMatchInlineSnapshot(` +Object { + "fromContext": "PT2H", + "source": "PT1H", + "target": "PT1H", +} +`); + + expect( + object({ + source: duration({ defaultValue: momentDuration(1, 'hour') }), + target: duration({ defaultValue: siblingRef('source') }), + fromContext: duration({ defaultValue: contextRef('val') }), + }).validate(undefined, { val: momentDuration(2, 'hour') }) + ).toMatchInlineSnapshot(` +Object { + "fromContext": "PT2H", + "source": "PT1H", + "target": "PT1H", +} +`); + }); }); test('returns error when not string or non-safe positive integer', () => { diff --git a/packages/kbn-config-schema/src/types/duration_type.ts b/packages/kbn-config-schema/src/types/duration_type.ts index 4d5ed952b7296..c95b6b9ddcadf 100644 --- a/packages/kbn-config-schema/src/types/duration_type.ts +++ b/packages/kbn-config-schema/src/types/duration_type.ts @@ -21,20 +21,33 @@ import typeDetect from 'type-detect'; import { Duration, ensureDuration } from '../duration'; import { SchemaTypeError } from '../errors'; import { internals } from '../internals'; +import { Reference } from '../references'; import { Type } from './type'; +type DurationValueType = Duration | string | number; + export interface DurationOptions { // we need to special-case defaultValue as we want to handle string inputs too + defaultValue?: DurationValueType | Reference | (() => DurationValueType); validate?: (value: Duration) => string | void; - defaultValue?: Duration | string | number; } export class DurationType extends Type { constructor(options: DurationOptions = {}) { - super(internals.duration(), { - ...options, - defaultValue: ensureDuration(options.defaultValue), - }); + let defaultValue; + if (typeof options.defaultValue === 'function') { + const originalDefaultValue = options.defaultValue; + defaultValue = () => ensureDuration(originalDefaultValue()); + } else if ( + typeof options.defaultValue === 'string' || + typeof options.defaultValue === 'number' + ) { + defaultValue = ensureDuration(options.defaultValue); + } else { + defaultValue = options.defaultValue; + } + + super(internals.duration(), { ...options, defaultValue }); } protected handleError(type: string, { message, value }: Record, path: string[]) { diff --git a/packages/kbn-config-schema/src/types/index.ts b/packages/kbn-config-schema/src/types/index.ts index 0a0aa308ebc94..4dd689425a781 100644 --- a/packages/kbn-config-schema/src/types/index.ts +++ b/packages/kbn-config-schema/src/types/index.ts @@ -32,3 +32,4 @@ export { ObjectType, Props, TypeOf } from './object_type'; export { RecordOfOptions, RecordOfType } from './record_type'; export { StringOptions, StringType } from './string_type'; export { UnionType } from './union_type'; +export { URIOptions, URIType } from './uri_type'; diff --git a/packages/kbn-config-schema/src/types/uri_type.test.ts b/packages/kbn-config-schema/src/types/uri_type.test.ts new file mode 100644 index 0000000000000..1345b47a63c1f --- /dev/null +++ b/packages/kbn-config-schema/src/types/uri_type.test.ts @@ -0,0 +1,144 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { schema } from '..'; + +test('is required by default', () => { + expect(() => schema.uri().validate(undefined)).toThrowErrorMatchingSnapshot(); +}); + +test('returns value for valid URI as per RFC3986', () => { + const uriSchema = schema.uri(); + + expect(uriSchema.validate('http://tools.ietf.org/html/rfc3986')).toBe( + 'http://tools.ietf.org/html/rfc3986' + ); + expect(uriSchema.validate('udp://3domain.local')).toBe('udp://3domain.local'); + expect(uriSchema.validate('urn:elastic:kibana')).toBe('urn:elastic:kibana'); + expect(uriSchema.validate('ftp://ftp.ietf.org/rfc/rfc3986.txt')).toBe( + 'ftp://ftp.ietf.org/rfc/rfc3986.txt' + ); + expect(uriSchema.validate('mailto:Platform.Kibana@elastic.co')).toBe( + 'mailto:Platform.Kibana@elastic.co' + ); + expect(uriSchema.validate('tel:+500-111-222-333')).toBe('tel:+500-111-222-333'); + expect(uriSchema.validate('file:///kibana.log')).toBe('file:///kibana.log'); + expect(uriSchema.validate('http://elastic@localhost:9200')).toBe('http://elastic@localhost:9200'); + expect(uriSchema.validate('http://elastic:changeme@localhost:9200')).toBe( + 'http://elastic:changeme@localhost:9200' + ); + expect(uriSchema.validate('ldap://[2001:db8::7]/c=GB?objectClass?one')).toBe( + 'ldap://[2001:db8::7]/c=GB?objectClass?one' + ); + + const uriWithMaxAllowedLength = `http://${'a'.repeat(255)}`; + expect(uriSchema.validate(uriWithMaxAllowedLength)).toBe(uriWithMaxAllowedLength); +}); + +test('returns error when value is not a URI', () => { + const uriSchema = schema.uri(); + + expect(() => uriSchema.validate('3domain.local')).toThrowErrorMatchingSnapshot(); + expect(() => + uriSchema.validate('http://8010:0:0:0:9:500:300C:200A') + ).toThrowErrorMatchingSnapshot(); + expect(() => uriSchema.validate('-')).toThrowErrorMatchingSnapshot(); + expect(() => + uriSchema.validate('https://example.com?baz[]=foo&baz[]=bar') + ).toThrowErrorMatchingSnapshot(); + + const tooLongUri = `http://${'a'.repeat(256)}`; + expect(() => uriSchema.validate(tooLongUri)).toThrowErrorMatchingSnapshot(); +}); + +describe('#scheme', () => { + test('returns value when URI has required scheme', () => { + const uriSchema = schema.uri({ scheme: ['http', 'https'] }); + + expect(uriSchema.validate('http://elastic.co')).toBe('http://elastic.co'); + expect(uriSchema.validate('https://elastic.co')).toBe('https://elastic.co'); + }); + + test('returns error when shorter string', () => { + const uriSchema = schema.uri({ scheme: ['http', 'https'] }); + + expect(() => uriSchema.validate('ftp://elastic.co')).toThrowErrorMatchingSnapshot(); + expect(() => uriSchema.validate('file:///kibana.log')).toThrowErrorMatchingSnapshot(); + }); +}); + +describe('#defaultValue', () => { + test('returns default when URI is undefined', () => { + expect(schema.uri({ defaultValue: 'http://localhost:9200' }).validate(undefined)).toBe( + 'http://localhost:9200' + ); + }); + + test('returns value when specified', () => { + expect( + schema.uri({ defaultValue: 'http://localhost:9200' }).validate('http://kibana.local') + ).toBe('http://kibana.local'); + }); + + test('returns value from context when context reference is specified', () => { + expect( + schema.uri({ defaultValue: schema.contextRef('some_uri') }).validate(undefined, { + some_uri: 'http://kibana.local', + }) + ).toBe('http://kibana.local'); + }); +}); + +describe('#validate', () => { + test('is called with input value', () => { + let calledWith; + + const validator = (val: any) => { + calledWith = val; + }; + + schema.uri({ validate: validator }).validate('http://kibana.local'); + + expect(calledWith).toBe('http://kibana.local'); + }); + + test('is not called with default value in no input', () => { + const validate = jest.fn(); + + schema.uri({ validate, defaultValue: 'http://kibana.local' }).validate(undefined); + + expect(validate).not.toHaveBeenCalled(); + }); + + test('throws when returns string', () => { + const validate = () => 'validator failure'; + + expect(() => + schema.uri({ validate }).validate('http://kibana.local') + ).toThrowErrorMatchingSnapshot(); + }); +}); + +test('returns error when not string', () => { + expect(() => schema.uri().validate(123)).toThrowErrorMatchingSnapshot(); + + expect(() => schema.uri().validate([1, 2, 3])).toThrowErrorMatchingSnapshot(); + + expect(() => schema.uri().validate(/abc/)).toThrowErrorMatchingSnapshot(); +}); diff --git a/packages/kbn-config-schema/src/types/uri_type.ts b/packages/kbn-config-schema/src/types/uri_type.ts new file mode 100644 index 0000000000000..f283554de527e --- /dev/null +++ b/packages/kbn-config-schema/src/types/uri_type.ts @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 typeDetect from 'type-detect'; +import { internals } from '../internals'; +import { Type, TypeOptions } from './type'; + +export type URIOptions = TypeOptions & { + scheme?: string | string[]; +}; + +export class URIType extends Type { + constructor(options: URIOptions = {}) { + super(internals.string().uri({ scheme: options.scheme }), options); + } + + protected handleError(type: string, { value, scheme }: Record) { + switch (type) { + case 'any.required': + case 'string.base': + return `expected value of type [string] but got [${typeDetect(value)}].`; + case 'string.uriCustomScheme': + return `expected URI with scheme [${scheme}] but but got [${value}].`; + case 'string.uri': + return `value is [${value}] but it must be a valid URI (see RFC 3986).`; + } + } +} diff --git a/packages/kbn-config-schema/tsconfig.json b/packages/kbn-config-schema/tsconfig.json index 3b1982520da06..f6c61268da17c 100644 --- a/packages/kbn-config-schema/tsconfig.json +++ b/packages/kbn-config-schema/tsconfig.json @@ -1,21 +1,21 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "declaration": true, - "declarationDir": "./target/types", - "outDir": "./target/out", - "stripInternal": true, - "declarationMap": true, - "types": [ - "jest", - "node" - ] - }, - "include": [ - "./types/joi.d.ts", - "./src/**/*.ts" - ], - "exclude": [ - "target" - ] -} +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "declaration": true, + "declarationDir": "./target/types", + "outDir": "./target/out", + "stripInternal": true, + "declarationMap": true, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "./types/joi.d.ts", + "./src/**/*.ts" + ], + "exclude": [ + "target" + ] +} diff --git a/packages/kbn-es-query/package.json b/packages/kbn-es-query/package.json index 70d21f60121b5..09682ae7ede31 100644 --- a/packages/kbn-es-query/package.json +++ b/packages/kbn-es-query/package.json @@ -15,17 +15,17 @@ }, "devDependencies": { "@babel/cli": "^7.2.3", - "@babel/core": "^7.2.2", - "@babel/plugin-proposal-class-properties": "^7.3.0", - "@babel/plugin-proposal-object-rest-spread": "^7.3.1", - "@babel/preset-env": "^7.3.1", - "@babel/preset-typescript": "^7.1.0", + "@babel/core": "^7.3.4", + "@babel/plugin-proposal-class-properties": "^7.3.4", + "@babel/plugin-proposal-object-rest-spread": "^7.3.4", + "@babel/preset-env": "^7.3.4", + "@babel/preset-typescript": "^7.3.3", "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", - "expect.js": "0.3.1", "del": "^3.0.0", + "expect.js": "0.3.1", "getopts": "^2.2.3", "supports-color": "^6.1.0", - "typescript": "^3.0.3" + "typescript": "^3.3.3333" } } diff --git a/packages/kbn-es-query/src/kuery/ast/kuery.js b/packages/kbn-es-query/src/kuery/ast/kuery.js index 21bf0885cfa59..b0fb04b664506 100644 --- a/packages/kbn-es-query/src/kuery/ast/kuery.js +++ b/packages/kbn-es-query/src/kuery/ast/kuery.js @@ -208,30 +208,31 @@ module.exports = (function() { peg$c44 = function() { return '\t'; }, peg$c45 = "\\r", peg$c46 = { type: "literal", value: "\\r", description: "\"\\\\r\"" }, - peg$c47 = "\\n", - peg$c48 = { type: "literal", value: "\\n", description: "\"\\\\n\"" }, - peg$c49 = function() { return '\n'; }, - peg$c50 = function(keyword) { return keyword; }, - peg$c51 = /^[\\():<>"*]/, - peg$c52 = { type: "class", value: "[\\\\():<>\"*]", description: "[\\\\():<>\"*]" }, - peg$c53 = "<=", - peg$c54 = { type: "literal", value: "<=", description: "\"<=\"" }, - peg$c55 = function() { return 'lte'; }, - peg$c56 = ">=", - peg$c57 = { type: "literal", value: ">=", description: "\">=\"" }, - peg$c58 = function() { return 'gte'; }, - peg$c59 = "<", - peg$c60 = { type: "literal", value: "<", description: "\"<\"" }, - peg$c61 = function() { return 'lt'; }, - peg$c62 = ">", - peg$c63 = { type: "literal", value: ">", description: "\">\"" }, - peg$c64 = function() { return 'gt'; }, - peg$c65 = /^[ \t\r\n]/, - peg$c66 = { type: "class", value: "[\\ \\t\\r\\n]", description: "[\\ \\t\\r\\n]" }, - peg$c67 = function() { return parseCursor; }, - peg$c68 = "@kuery-cursor@", - peg$c69 = { type: "literal", value: "@kuery-cursor@", description: "\"@kuery-cursor@\"" }, - peg$c70 = function() { return cursorSymbol; }, + peg$c47 = function() { return '\r'; }, + peg$c48 = "\\n", + peg$c49 = { type: "literal", value: "\\n", description: "\"\\\\n\"" }, + peg$c50 = function() { return '\n'; }, + peg$c51 = function(keyword) { return keyword; }, + peg$c52 = /^[\\():<>"*]/, + peg$c53 = { type: "class", value: "[\\\\():<>\"*]", description: "[\\\\():<>\"*]" }, + peg$c54 = "<=", + peg$c55 = { type: "literal", value: "<=", description: "\"<=\"" }, + peg$c56 = function() { return 'lte'; }, + peg$c57 = ">=", + peg$c58 = { type: "literal", value: ">=", description: "\">=\"" }, + peg$c59 = function() { return 'gte'; }, + peg$c60 = "<", + peg$c61 = { type: "literal", value: "<", description: "\"<\"" }, + peg$c62 = function() { return 'lt'; }, + peg$c63 = ">", + peg$c64 = { type: "literal", value: ">", description: "\">\"" }, + peg$c65 = function() { return 'gt'; }, + peg$c66 = /^[ \t\r\n]/, + peg$c67 = { type: "class", value: "[\\ \\t\\r\\n]", description: "[\\ \\t\\r\\n]" }, + peg$c68 = function() { return parseCursor; }, + peg$c69 = "@kuery-cursor@", + peg$c70 = { type: "literal", value: "@kuery-cursor@", description: "\"@kuery-cursor@\"" }, + peg$c71 = function() { return cursorSymbol; }, peg$currPos = 0, peg$savedPos = 0, @@ -1477,21 +1478,21 @@ module.exports = (function() { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c44(); + s1 = peg$c47(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c47) { - s1 = peg$c47; + if (input.substr(peg$currPos, 2) === peg$c48) { + s1 = peg$c48; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c48); } + if (peg$silentFails === 0) { peg$fail(peg$c49); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c49(); + s1 = peg$c50(); } s0 = s1; } @@ -1568,7 +1569,7 @@ module.exports = (function() { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c50(s2); + s1 = peg$c51(s2); s0 = s1; } else { peg$currPos = s0; @@ -1599,12 +1600,12 @@ module.exports = (function() { function peg$parseSpecialCharacter() { var s0; - if (peg$c51.test(input.charAt(peg$currPos))) { + if (peg$c52.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c52); } + if (peg$silentFails === 0) { peg$fail(peg$c53); } } return s0; @@ -1614,58 +1615,58 @@ module.exports = (function() { var s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c53) { - s1 = peg$c53; + if (input.substr(peg$currPos, 2) === peg$c54) { + s1 = peg$c54; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c54); } + if (peg$silentFails === 0) { peg$fail(peg$c55); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c55(); + s1 = peg$c56(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c56) { - s1 = peg$c56; + if (input.substr(peg$currPos, 2) === peg$c57) { + s1 = peg$c57; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c57); } + if (peg$silentFails === 0) { peg$fail(peg$c58); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c58(); + s1 = peg$c59(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c59; + s1 = peg$c60; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c60); } + if (peg$silentFails === 0) { peg$fail(peg$c61); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c61(); + s1 = peg$c62(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c62; + s1 = peg$c63; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c63); } + if (peg$silentFails === 0) { peg$fail(peg$c64); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c64(); + s1 = peg$c65(); } s0 = s1; } @@ -1678,12 +1679,12 @@ module.exports = (function() { function peg$parseSpace() { var s0; - if (peg$c65.test(input.charAt(peg$currPos))) { + if (peg$c66.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c66); } + if (peg$silentFails === 0) { peg$fail(peg$c67); } } return s0; @@ -1694,23 +1695,23 @@ module.exports = (function() { s0 = peg$currPos; peg$savedPos = peg$currPos; - s1 = peg$c67(); + s1 = peg$c68(); if (s1) { s1 = void 0; } else { s1 = peg$FAILED; } if (s1 !== peg$FAILED) { - if (input.substr(peg$currPos, 14) === peg$c68) { - s2 = peg$c68; + if (input.substr(peg$currPos, 14) === peg$c69) { + s2 = peg$c69; peg$currPos += 14; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c69); } + if (peg$silentFails === 0) { peg$fail(peg$c70); } } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c70(); + s1 = peg$c71(); s0 = s1; } else { peg$currPos = s0; diff --git a/packages/kbn-es-query/src/kuery/ast/kuery.peg b/packages/kbn-es-query/src/kuery/ast/kuery.peg index 62711df56c991..e459e319bc585 100644 --- a/packages/kbn-es-query/src/kuery/ast/kuery.peg +++ b/packages/kbn-es-query/src/kuery/ast/kuery.peg @@ -252,7 +252,7 @@ OptionalSpace EscapedWhitespace = '\\t' { return '\t'; } - / '\\r' { return '\t'; } + / '\\r' { return '\r'; } / '\\n' { return '\n'; } EscapedSpecialCharacter diff --git a/packages/kbn-i18n/package.json b/packages/kbn-i18n/package.json index 4cdba0ac1317a..9d915fdf8ec6b 100644 --- a/packages/kbn-i18n/package.json +++ b/packages/kbn-i18n/package.json @@ -13,19 +13,19 @@ }, "devDependencies": { "@babel/cli": "^7.2.3", - "@babel/core": "^7.2.2", - "@babel/plugin-proposal-class-properties": "^7.3.0", - "@babel/plugin-proposal-object-rest-spread": "^7.3.1", - "@babel/preset-env": "^7.3.1", + "@babel/core": "^7.3.4", + "@babel/plugin-proposal-class-properties": "^7.3.4", + "@babel/plugin-proposal-object-rest-spread": "^7.3.4", + "@babel/preset-env": "^7.3.4", "@babel/preset-react": "^7.0.0", - "@babel/preset-typescript": "^7.1.0", + "@babel/preset-typescript": "^7.3.3", "@kbn/dev-utils": "1.0.0", "@types/intl-relativeformat": "^2.1.0", "@types/react-intl": "^2.3.15", "del": "^3.0.0", "getopts": "^2.2.3", "supports-color": "^6.1.0", - "typescript": "^3.0.3" + "typescript": "^3.3.3333" }, "dependencies": { "intl-format-cache": "^2.1.0", diff --git a/packages/kbn-i18n/src/core/i18n.test.ts b/packages/kbn-i18n/src/core/i18n.test.ts index 96472fd9d8223..ffdf9f8e2bcaf 100644 --- a/packages/kbn-i18n/src/core/i18n.test.ts +++ b/packages/kbn-i18n/src/core/i18n.test.ts @@ -885,7 +885,7 @@ describe('I18n engine', () => { }); describe('load', () => { - let mockFetch: jest.Mock; + let mockFetch: jest.Mock; beforeEach(() => { mockFetch = jest.spyOn(global as any, 'fetch').mockImplementation(); }); diff --git a/packages/kbn-interpreter/src/public/batched_fetch.js b/packages/kbn-interpreter/src/public/batched_fetch.js index 20fd0d37b5ef9..414b1443f5b81 100644 --- a/packages/kbn-interpreter/src/public/batched_fetch.js +++ b/packages/kbn-interpreter/src/public/batched_fetch.js @@ -23,7 +23,7 @@ import { FUNCTIONS_URL } from './consts'; * Create a function which executes an Expression function on the * server as part of a larger batch of executions. */ -export function batchedFetch({ kfetch, serialize, ms = 10 }) { +export function batchedFetch({ ajaxStream, serialize, ms = 10 }) { // Uniquely identifies each function call in a batch operation // so that the appropriate promise can be resolved / rejected later. let id = 0; @@ -42,7 +42,7 @@ export function batchedFetch({ kfetch, serialize, ms = 10 }) { }; const runBatch = () => { - processBatch(kfetch, batch); + processBatch(ajaxStream, batch); reset(); }; @@ -70,14 +70,15 @@ export function batchedFetch({ kfetch, serialize, ms = 10 }) { function createFuture() { let resolve; let reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); return { - resolve(val) { return resolve(val); }, - reject(val) { return reject(val); }, - promise: new Promise((res, rej) => { - resolve = res; - reject = rej; - }), + resolve, + reject, + promise, }; } @@ -85,22 +86,21 @@ function createFuture() { * Runs the specified batch of functions on the server, then resolves * the related promises. */ -async function processBatch(kfetch, batch) { +async function processBatch(ajaxStream, batch) { try { - const { results } = await kfetch({ - pathname: FUNCTIONS_URL, - method: 'POST', + await ajaxStream({ + url: FUNCTIONS_URL, body: JSON.stringify({ functions: Object.values(batch).map(({ request }) => request), }), - }); + onResponse({ id, statusCode, result }) { + const { future } = batch[id]; - results.forEach(({ id, result }) => { - const { future } = batch[id]; - if (result.statusCode && result.err) { - future.reject(result); - } else { - future.resolve(result); + if (statusCode >= 400) { + future.reject(result); + } else { + future.resolve(result); + } } }); } catch (err) { diff --git a/packages/kbn-interpreter/src/public/batched_fetch.test.js b/packages/kbn-interpreter/src/public/batched_fetch.test.js new file mode 100644 index 0000000000000..fbd8bcbe544d0 --- /dev/null +++ b/packages/kbn-interpreter/src/public/batched_fetch.test.js @@ -0,0 +1,72 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { batchedFetch } from './batched_fetch'; + +const serialize = (o) => JSON.stringify(o); + +describe('batchedFetch', () => { + it('resolves the correct promise', async () => { + const ajaxStream = jest.fn(async ({ body, onResponse }) => { + const { functions } = JSON.parse(body); + functions.map(({ id, functionName, context, args }) => onResponse({ + id, + statusCode: 200, + result: `${functionName}${context}${args}`, + })); + }); + + const ajax = batchedFetch({ ajaxStream, serialize, ms: 1 }); + + const result = await Promise.all([ + ajax({ functionName: 'a', context: 1, args: 'aaa' }), + ajax({ functionName: 'b', context: 2, args: 'bbb' }), + ]); + + expect(result).toEqual([ + 'a1aaa', + 'b2bbb', + ]); + }); + + it('rejects responses whose statusCode is >= 300', async () => { + const ajaxStream = jest.fn(async ({ body, onResponse }) => { + const { functions } = JSON.parse(body); + functions.map(({ id, functionName, context, args }) => onResponse({ + id, + statusCode: context, + result: context >= 400 ? { err: {} } : `${functionName}${context}${args}`, + })); + }); + + const ajax = batchedFetch({ ajaxStream, serialize, ms: 1 }); + + const result = await Promise.all([ + ajax({ functionName: 'a', context: 500, args: 'aaa' }).catch(() => 'fail'), + ajax({ functionName: 'b', context: 400, args: 'bbb' }).catch(() => 'fail'), + ajax({ functionName: 'c', context: 200, args: 'ccc' }), + ]); + + expect(result).toEqual([ + 'fail', + 'fail', + 'c200ccc' + ]); + }); +}); diff --git a/packages/kbn-interpreter/src/public/interpreter.js b/packages/kbn-interpreter/src/public/interpreter.js index 9e695864e1f45..02adc19f7810a 100644 --- a/packages/kbn-interpreter/src/public/interpreter.js +++ b/packages/kbn-interpreter/src/public/interpreter.js @@ -23,11 +23,11 @@ import { createHandlers } from './create_handlers'; import { batchedFetch } from './batched_fetch'; import { FUNCTIONS_URL } from './consts'; -export async function initializeInterpreter(kfetch, typesRegistry, functionsRegistry) { +export async function initializeInterpreter({ kfetch, ajaxStream, typesRegistry, functionsRegistry }) { const serverFunctionList = await kfetch({ pathname: FUNCTIONS_URL }); const types = typesRegistry.toJS(); const { serialize } = serializeProvider(types); - const batch = batchedFetch({ kfetch, serialize }); + const batch = batchedFetch({ ajaxStream, serialize }); // For every sever-side function, register a client-side // function that matches its definition, but which simply diff --git a/packages/kbn-interpreter/src/public/interpreter.test.js b/packages/kbn-interpreter/src/public/interpreter.test.js index 34eb3578ec35c..8593d0793a1be 100644 --- a/packages/kbn-interpreter/src/public/interpreter.test.js +++ b/packages/kbn-interpreter/src/public/interpreter.test.js @@ -35,26 +35,21 @@ jest.mock('./create_handlers', () => ({ describe('kbn-interpreter/interpreter', () => { it('loads server-side functions', async () => { const kfetch = jest.fn(async () => ({})); + const ajaxStream = jest.fn(async () => ({})); - await initializeInterpreter(kfetch, { toJS: () => ({}) }, ({ register: () => {} })); + await initializeInterpreter({ + kfetch, + ajaxStream, + typesRegistry: { toJS: () => ({}) }, + functionsRegistry: ({ register: () => {} }), + }); expect(kfetch).toHaveBeenCalledTimes(1); expect(kfetch).toHaveBeenCalledWith({ pathname: FUNCTIONS_URL }); }); it('registers client-side functions that pass through to the server', async () => { - const kfetch = jest.fn(async ({ method }) => { - if (method === 'POST') { - return { - results: [{ - id: 1, - result: { - hello: 'world', - }, - }], - }; - } - + const kfetch = jest.fn(async () => { return { hello: { name: 'hello' }, world: { name: 'world' }, @@ -62,8 +57,16 @@ describe('kbn-interpreter/interpreter', () => { }); const register = jest.fn(); + const ajaxStream = jest.fn(async ({ onResponse }) => { + onResponse({ id: 1, result: { hello: 'world' } }); + }); - await initializeInterpreter(kfetch, { toJS: () => ({}) }, ({ register })); + await initializeInterpreter({ + kfetch, + ajaxStream, + typesRegistry: { toJS: () => ({}) }, + functionsRegistry: ({ register }), + }); expect(register).toHaveBeenCalledTimes(2); @@ -81,9 +84,9 @@ describe('kbn-interpreter/interpreter', () => { expect(result).toEqual({ hello: 'world' }); - expect(kfetch).toHaveBeenCalledWith({ - pathname: FUNCTIONS_URL, - method: 'POST', + expect(ajaxStream).toHaveBeenCalledWith({ + url: FUNCTIONS_URL, + onResponse: expect.any(Function), body: JSON.stringify({ functions: [{ id: 1, diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 43c4337521ec4..dc5d895c80148 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -105,7 +105,7 @@ Object.defineProperty(exports, 'run', { } }); -var _production = __webpack_require__(371); +var _production = __webpack_require__(367); Object.defineProperty(exports, 'buildProductionProjects', { enumerable: true, @@ -120,7 +120,7 @@ Object.defineProperty(exports, 'prepareExternalProjectDependencies', { } }); -var _workspaces = __webpack_require__(134); +var _workspaces = __webpack_require__(131); Object.defineProperty(exports, 'copyWorkspacePackages', { enumerable: true, @@ -198,7 +198,7 @@ var _path = __webpack_require__(16); var _commands = __webpack_require__(17); -var _run = __webpack_require__(361); +var _run = __webpack_require__(357); var _log = __webpack_require__(33); @@ -2464,11 +2464,11 @@ exports.commands = undefined; var _bootstrap = __webpack_require__(18); -var _clean = __webpack_require__(136); +var _clean = __webpack_require__(133); -var _run = __webpack_require__(159); +var _run = __webpack_require__(155); -var _watch = __webpack_require__(160); +var _watch = __webpack_require__(156); /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -4368,7 +4368,7 @@ var _errors = __webpack_require__(52); var _project = __webpack_require__(53); -var _workspaces = __webpack_require__(134); +var _workspaces = __webpack_require__(131); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -7934,7 +7934,7 @@ var _log = __webpack_require__(33); var _package_json = __webpack_require__(54); -var _scripts = __webpack_require__(95); +var _scripts = __webpack_require__(92); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -8077,7 +8077,7 @@ var _readPkg = __webpack_require__(55); var _readPkg2 = _interopRequireDefault(_readPkg); -var _writePkg = __webpack_require__(83); +var _writePkg = __webpack_require__(82); var _writePkg2 = _interopRequireDefault(_writePkg); @@ -8137,7 +8137,7 @@ module.exports = (fp, opts) => { }) .then(x => { if (opts.normalize !== false) { - __webpack_require__(65)(x); + __webpack_require__(64)(x); } return x; @@ -8156,7 +8156,7 @@ module.exports.sync = (fp, opts) => { const x = loadJsonFile.sync(fp); if (opts.normalize !== false) { - __webpack_require__(65)(x); + __webpack_require__(64)(x); } return x; @@ -8536,7 +8536,7 @@ module.exports = (obj, opts) => { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(64); +const pify = __webpack_require__(62); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -8582,103 +8582,12 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /* 64 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - - -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); - - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } - - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); - } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } - - resolve(results); - } else { - resolve(result); - } - }); - } - - fn.apply(this, args); - }); -}; - -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); - - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); - }; - - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } - - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; - } - - return ret; -}; - - -/***/ }), -/* 65 */ -/***/ (function(module, exports, __webpack_require__) { - module.exports = normalize -var fixer = __webpack_require__(66) +var fixer = __webpack_require__(65) normalize.fixer = fixer -var makeWarning = __webpack_require__(81) +var makeWarning = __webpack_require__(80) var fieldsToFix = ['name','version','description','repository','modules','scripts' ,'files','bin','man','bugs','keywords','readme','homepage','license'] @@ -8715,17 +8624,17 @@ function ucFirst (string) { /***/ }), -/* 66 */ +/* 65 */ /***/ (function(module, exports, __webpack_require__) { -var semver = __webpack_require__(67) -var validateLicense = __webpack_require__(68); -var hostedGitInfo = __webpack_require__(73) -var isBuiltinModule = __webpack_require__(77) +var semver = __webpack_require__(66) +var validateLicense = __webpack_require__(67); +var hostedGitInfo = __webpack_require__(72) +var isBuiltinModule = __webpack_require__(76) var depTypes = ["dependencies","devDependencies","optionalDependencies"] -var extractDescription = __webpack_require__(79) -var url = __webpack_require__(74) -var typos = __webpack_require__(80) +var extractDescription = __webpack_require__(78) +var url = __webpack_require__(73) +var typos = __webpack_require__(79) var fixer = module.exports = { // default warning function @@ -9138,7 +9047,7 @@ function bugsTypos(bugs, warn) { /***/ }), -/* 67 */ +/* 66 */ /***/ (function(module, exports) { exports = module.exports = SemVer; @@ -10440,11 +10349,11 @@ function intersects(r1, r2, loose) { /***/ }), -/* 68 */ +/* 67 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(69); -var correct = __webpack_require__(71); +var parse = __webpack_require__(68); +var correct = __webpack_require__(70); var genericWarning = ( 'license should be ' + @@ -10530,10 +10439,10 @@ module.exports = function(argument) { /***/ }), -/* 69 */ +/* 68 */ /***/ (function(module, exports, __webpack_require__) { -var parser = __webpack_require__(70).parser +var parser = __webpack_require__(69).parser module.exports = function (argument) { return parser.parse(argument) @@ -10541,7 +10450,7 @@ module.exports = function (argument) { /***/ }), -/* 70 */ +/* 69 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(module) {/* parser generated by jison 0.4.17 */ @@ -11905,10 +11814,10 @@ if ( true && __webpack_require__.c[__webpack_require__.s] === module) { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 71 */ +/* 70 */ /***/ (function(module, exports, __webpack_require__) { -var licenseIDs = __webpack_require__(72); +var licenseIDs = __webpack_require__(71); function valid(string) { return licenseIDs.indexOf(string) > -1; @@ -12148,20 +12057,20 @@ module.exports = function(identifier) { /***/ }), -/* 72 */ +/* 71 */ /***/ (function(module) { module.exports = ["Glide","Abstyles","AFL-1.1","AFL-1.2","AFL-2.0","AFL-2.1","AFL-3.0","AMPAS","APL-1.0","Adobe-Glyph","APAFML","Adobe-2006","AGPL-1.0","Afmparse","Aladdin","ADSL","AMDPLPA","ANTLR-PD","Apache-1.0","Apache-1.1","Apache-2.0","AML","APSL-1.0","APSL-1.1","APSL-1.2","APSL-2.0","Artistic-1.0","Artistic-1.0-Perl","Artistic-1.0-cl8","Artistic-2.0","AAL","Bahyph","Barr","Beerware","BitTorrent-1.0","BitTorrent-1.1","BSL-1.0","Borceux","BSD-2-Clause","BSD-2-Clause-FreeBSD","BSD-2-Clause-NetBSD","BSD-3-Clause","BSD-3-Clause-Clear","BSD-4-Clause","BSD-Protection","BSD-Source-Code","BSD-3-Clause-Attribution","0BSD","BSD-4-Clause-UC","bzip2-1.0.5","bzip2-1.0.6","Caldera","CECILL-1.0","CECILL-1.1","CECILL-2.0","CECILL-2.1","CECILL-B","CECILL-C","ClArtistic","MIT-CMU","CNRI-Jython","CNRI-Python","CNRI-Python-GPL-Compatible","CPOL-1.02","CDDL-1.0","CDDL-1.1","CPAL-1.0","CPL-1.0","CATOSL-1.1","Condor-1.1","CC-BY-1.0","CC-BY-2.0","CC-BY-2.5","CC-BY-3.0","CC-BY-4.0","CC-BY-ND-1.0","CC-BY-ND-2.0","CC-BY-ND-2.5","CC-BY-ND-3.0","CC-BY-ND-4.0","CC-BY-NC-1.0","CC-BY-NC-2.0","CC-BY-NC-2.5","CC-BY-NC-3.0","CC-BY-NC-4.0","CC-BY-NC-ND-1.0","CC-BY-NC-ND-2.0","CC-BY-NC-ND-2.5","CC-BY-NC-ND-3.0","CC-BY-NC-ND-4.0","CC-BY-NC-SA-1.0","CC-BY-NC-SA-2.0","CC-BY-NC-SA-2.5","CC-BY-NC-SA-3.0","CC-BY-NC-SA-4.0","CC-BY-SA-1.0","CC-BY-SA-2.0","CC-BY-SA-2.5","CC-BY-SA-3.0","CC-BY-SA-4.0","CC0-1.0","Crossword","CrystalStacker","CUA-OPL-1.0","Cube","curl","D-FSL-1.0","diffmark","WTFPL","DOC","Dotseqn","DSDP","dvipdfm","EPL-1.0","ECL-1.0","ECL-2.0","eGenix","EFL-1.0","EFL-2.0","MIT-advertising","MIT-enna","Entessa","ErlPL-1.1","EUDatagrid","EUPL-1.0","EUPL-1.1","Eurosym","Fair","MIT-feh","Frameworx-1.0","FreeImage","FTL","FSFAP","FSFUL","FSFULLR","Giftware","GL2PS","Glulxe","AGPL-3.0","GFDL-1.1","GFDL-1.2","GFDL-1.3","GPL-1.0","GPL-2.0","GPL-3.0","LGPL-2.1","LGPL-3.0","LGPL-2.0","gnuplot","gSOAP-1.3b","HaskellReport","HPND","IBM-pibs","IPL-1.0","ICU","ImageMagick","iMatix","Imlib2","IJG","Info-ZIP","Intel-ACPI","Intel","Interbase-1.0","IPA","ISC","JasPer-2.0","JSON","LPPL-1.0","LPPL-1.1","LPPL-1.2","LPPL-1.3a","LPPL-1.3c","Latex2e","BSD-3-Clause-LBNL","Leptonica","LGPLLR","Libpng","libtiff","LAL-1.2","LAL-1.3","LiLiQ-P-1.1","LiLiQ-Rplus-1.1","LiLiQ-R-1.1","LPL-1.02","LPL-1.0","MakeIndex","MTLL","MS-PL","MS-RL","MirOS","MITNFA","MIT","Motosoto","MPL-1.0","MPL-1.1","MPL-2.0","MPL-2.0-no-copyleft-exception","mpich2","Multics","Mup","NASA-1.3","Naumen","NBPL-1.0","NetCDF","NGPL","NOSL","NPL-1.0","NPL-1.1","Newsletr","NLPL","Nokia","NPOSL-3.0","NLOD-1.0","Noweb","NRL","NTP","Nunit","OCLC-2.0","ODbL-1.0","PDDL-1.0","OCCT-PL","OGTSL","OLDAP-2.2.2","OLDAP-1.1","OLDAP-1.2","OLDAP-1.3","OLDAP-1.4","OLDAP-2.0","OLDAP-2.0.1","OLDAP-2.1","OLDAP-2.2","OLDAP-2.2.1","OLDAP-2.3","OLDAP-2.4","OLDAP-2.5","OLDAP-2.6","OLDAP-2.7","OLDAP-2.8","OML","OPL-1.0","OSL-1.0","OSL-1.1","OSL-2.0","OSL-2.1","OSL-3.0","OpenSSL","OSET-PL-2.1","PHP-3.0","PHP-3.01","Plexus","PostgreSQL","psfrag","psutils","Python-2.0","QPL-1.0","Qhull","Rdisc","RPSL-1.0","RPL-1.1","RPL-1.5","RHeCos-1.1","RSCPL","RSA-MD","Ruby","SAX-PD","Saxpath","SCEA","SWL","SMPPL","Sendmail","SGI-B-1.0","SGI-B-1.1","SGI-B-2.0","OFL-1.0","OFL-1.1","SimPL-2.0","Sleepycat","SNIA","Spencer-86","Spencer-94","Spencer-99","SMLNJ","SugarCRM-1.1.3","SISSL","SISSL-1.2","SPL-1.0","Watcom-1.0","TCL","Unlicense","TMate","TORQUE-1.1","TOSL","Unicode-TOU","UPL-1.0","NCSA","Vim","VOSTROM","VSL-1.0","W3C-19980720","W3C","Wsuipa","Xnet","X11","Xerox","XFree86-1.1","xinetd","xpp","XSkat","YPL-1.0","YPL-1.1","Zed","Zend-2.0","Zimbra-1.3","Zimbra-1.4","Zlib","zlib-acknowledgement","ZPL-1.1","ZPL-2.0","ZPL-2.1","BSD-3-Clause-No-Nuclear-License","BSD-3-Clause-No-Nuclear-Warranty","BSD-3-Clause-No-Nuclear-License-2014","eCos-2.0","GPL-2.0-with-autoconf-exception","GPL-2.0-with-bison-exception","GPL-2.0-with-classpath-exception","GPL-2.0-with-font-exception","GPL-2.0-with-GCC-exception","GPL-3.0-with-autoconf-exception","GPL-3.0-with-GCC-exception","StandardML-NJ","WXwindows"]; /***/ }), -/* 73 */ +/* 72 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var url = __webpack_require__(74) -var gitHosts = __webpack_require__(75) -var GitHost = module.exports = __webpack_require__(76) +var url = __webpack_require__(73) +var gitHosts = __webpack_require__(74) +var GitHost = module.exports = __webpack_require__(75) var protocolToRepresentationMap = { 'git+ssh': 'sshurl', @@ -12282,13 +12191,13 @@ function parseGitUrl (giturl) { /***/ }), -/* 74 */ +/* 73 */ /***/ (function(module, exports) { module.exports = require("url"); /***/ }), -/* 75 */ +/* 74 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -12363,12 +12272,12 @@ Object.keys(gitHosts).forEach(function (name) { /***/ }), -/* 76 */ +/* 75 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var gitHosts = __webpack_require__(75) +var gitHosts = __webpack_require__(74) var extend = Object.assign || __webpack_require__(29)._extend var GitHost = module.exports = function (type, user, auth, project, committish, defaultRepresentation, opts) { @@ -12484,12 +12393,12 @@ GitHost.prototype.toString = function (opts) { /***/ }), -/* 77 */ +/* 76 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var builtinModules = __webpack_require__(78); +var builtinModules = __webpack_require__(77); module.exports = function (str) { if (typeof str !== 'string') { @@ -12501,7 +12410,7 @@ module.exports = function (str) { /***/ }), -/* 78 */ +/* 77 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -12518,7 +12427,7 @@ module.exports = Object.keys(process.binding('natives')).filter(function (el) { /***/ }), -/* 79 */ +/* 78 */ /***/ (function(module, exports) { module.exports = extractDescription @@ -12538,17 +12447,17 @@ function extractDescription (d) { /***/ }), -/* 80 */ +/* 79 */ /***/ (function(module) { module.exports = {"topLevel":{"dependancies":"dependencies","dependecies":"dependencies","depdenencies":"dependencies","devEependencies":"devDependencies","depends":"dependencies","dev-dependencies":"devDependencies","devDependences":"devDependencies","devDepenencies":"devDependencies","devdependencies":"devDependencies","repostitory":"repository","repo":"repository","prefereGlobal":"preferGlobal","hompage":"homepage","hampage":"homepage","autohr":"author","autor":"author","contributers":"contributors","publicationConfig":"publishConfig","script":"scripts"},"bugs":{"web":"url","name":"url"},"script":{"server":"start","tests":"test"}}; /***/ }), -/* 81 */ +/* 80 */ /***/ (function(module, exports, __webpack_require__) { var util = __webpack_require__(29) -var messages = __webpack_require__(82) +var messages = __webpack_require__(81) module.exports = function() { var args = Array.prototype.slice.call(arguments, 0) @@ -12573,20 +12482,20 @@ function makeTypoWarning (providedName, probableName, field) { /***/ }), -/* 82 */ +/* 81 */ /***/ (function(module) { module.exports = {"repositories":"'repositories' (plural) Not supported. Please pick one as the 'repository' field","missingRepository":"No repository field.","brokenGitUrl":"Probably broken git url: %s","nonObjectScripts":"scripts must be an object","nonStringScript":"script values must be string commands","nonArrayFiles":"Invalid 'files' member","invalidFilename":"Invalid filename in 'files' list: %s","nonArrayBundleDependencies":"Invalid 'bundleDependencies' list. Must be array of package names","nonStringBundleDependency":"Invalid bundleDependencies member: %s","nonDependencyBundleDependency":"Non-dependency in bundleDependencies: %s","nonObjectDependencies":"%s field must be an object","nonStringDependency":"Invalid dependency: %s %s","deprecatedArrayDependencies":"specifying %s as array is deprecated","deprecatedModules":"modules field is deprecated","nonArrayKeywords":"keywords should be an array of strings","nonStringKeyword":"keywords should be an array of strings","conflictingName":"%s is also the name of a node core module.","nonStringDescription":"'description' field should be a string","missingDescription":"No description","missingReadme":"No README data","missingLicense":"No license field.","nonEmailUrlBugsString":"Bug string field must be url, email, or {email,url}","nonUrlBugsUrlField":"bugs.url field must be a string url. Deleted.","nonEmailBugsEmailField":"bugs.email field must be a string email. Deleted.","emptyNormalizedBugs":"Normalized value of bugs field is an empty object. Deleted.","nonUrlHomepage":"homepage field must be a string url. Deleted.","invalidLicense":"license should be a valid SPDX license expression","typo":"%s should probably be %s."}; /***/ }), -/* 83 */ +/* 82 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const writeJsonFile = __webpack_require__(84); -const sortKeys = __webpack_require__(89); +const writeJsonFile = __webpack_require__(83); +const sortKeys = __webpack_require__(88); const opts = {detectIndent: true}; @@ -12639,18 +12548,18 @@ module.exports.sync = (fp, data) => { /***/ }), -/* 84 */ +/* 83 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); const fs = __webpack_require__(22); -const writeFileAtomic = __webpack_require__(85); -const sortKeys = __webpack_require__(89); -const makeDir = __webpack_require__(91); -const pify = __webpack_require__(93); -const detectIndent = __webpack_require__(94); +const writeFileAtomic = __webpack_require__(84); +const sortKeys = __webpack_require__(88); +const makeDir = __webpack_require__(90); +const pify = __webpack_require__(62); +const detectIndent = __webpack_require__(91); const init = (fn, fp, data, opts) => { if (!fp) { @@ -12719,7 +12628,7 @@ module.exports.sync = (fp, data, opts) => { /***/ }), -/* 85 */ +/* 84 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -12730,8 +12639,8 @@ module.exports._getTmpname = getTmpname // for testing module.exports._cleanupOnExit = cleanupOnExit var fs = __webpack_require__(22) -var MurmurHash3 = __webpack_require__(86) -var onExit = __webpack_require__(87) +var MurmurHash3 = __webpack_require__(85) +var onExit = __webpack_require__(86) var path = __webpack_require__(16) var activeFiles = {} @@ -12925,7 +12834,7 @@ function writeFileSync (filename, data, options) { /***/ }), -/* 86 */ +/* 85 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -13067,14 +12976,14 @@ function writeFileSync (filename, data, options) { /***/ }), -/* 87 */ +/* 86 */ /***/ (function(module, exports, __webpack_require__) { // Note: since nyc uses this module to output coverage, any lines // that are in the direct sync flow of nyc's outputCoverage are // ignored, since we can never get coverage for them. var assert = __webpack_require__(30) -var signals = __webpack_require__(88) +var signals = __webpack_require__(87) var EE = __webpack_require__(45) /* istanbul ignore if */ @@ -13230,7 +13139,7 @@ function processEmit (ev, arg) { /***/ }), -/* 88 */ +/* 87 */ /***/ (function(module, exports) { // This is not the set of all possible signals. @@ -13289,12 +13198,12 @@ if (process.platform === 'linux') { /***/ }), -/* 89 */ +/* 88 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const isPlainObj = __webpack_require__(90); +const isPlainObj = __webpack_require__(89); module.exports = (obj, opts) => { if (!isPlainObj(obj)) { @@ -13351,7 +13260,7 @@ module.exports = (obj, opts) => { /***/ }), -/* 90 */ +/* 89 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -13365,14 +13274,14 @@ module.exports = function (x) { /***/ }), -/* 91 */ +/* 90 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); const path = __webpack_require__(16); -const pify = __webpack_require__(92); +const pify = __webpack_require__(62); const defaults = { mode: 0o777 & (~process.umask()), @@ -13457,189 +13366,7 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 92 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); - - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } - - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); - } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } - - resolve(results); - } else { - resolve(result); - } - }); - } - - fn.apply(this, args); - }); -}; - -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); - - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); - }; - - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } - - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; - } - - return ret; -}; - - -/***/ }), -/* 93 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); - - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } - - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); - } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } - - resolve(results); - } else { - resolve(result); - } - }); - } - - fn.apply(this, args); - }); -}; - -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); - - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); - }; - - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } - - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; - } - - return ret; -}; - - -/***/ }), -/* 94 */ +/* 91 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -13768,7 +13495,7 @@ module.exports = str => { /***/ }), -/* 95 */ +/* 92 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -13820,7 +13547,7 @@ let runScriptInPackage = exports.runScriptInPackage = (() => { exports.runScriptInPackageStreaming = runScriptInPackageStreaming; -var _child_process = __webpack_require__(96); +var _child_process = __webpack_require__(93); function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -13852,7 +13579,7 @@ function runScriptInPackageStreaming(script, args, pkg) { } /***/ }), -/* 96 */ +/* 93 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -13889,15 +13616,15 @@ var _chalk = __webpack_require__(2); var _chalk2 = _interopRequireDefault(_chalk); -var _execa = __webpack_require__(97); +var _execa = __webpack_require__(94); var _execa2 = _interopRequireDefault(_execa); -var _logSymbols = __webpack_require__(125); +var _logSymbols = __webpack_require__(122); var _logSymbols2 = _interopRequireDefault(_logSymbols); -var _strongLogTransformer = __webpack_require__(126); +var _strongLogTransformer = __webpack_require__(123); var _strongLogTransformer2 = _interopRequireDefault(_strongLogTransformer); @@ -13931,22 +13658,22 @@ function spawnStreaming(command, args, opts, { prefix }) { } /***/ }), -/* 97 */ +/* 94 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const childProcess = __webpack_require__(98); -const crossSpawn = __webpack_require__(99); -const stripEof = __webpack_require__(114); -const npmRunPath = __webpack_require__(115); -const isStream = __webpack_require__(117); -const _getStream = __webpack_require__(118); -const pFinally = __webpack_require__(122); -const onExit = __webpack_require__(87); -const errname = __webpack_require__(123); -const stdio = __webpack_require__(124); +const childProcess = __webpack_require__(95); +const crossSpawn = __webpack_require__(96); +const stripEof = __webpack_require__(111); +const npmRunPath = __webpack_require__(112); +const isStream = __webpack_require__(114); +const _getStream = __webpack_require__(115); +const pFinally = __webpack_require__(119); +const onExit = __webpack_require__(86); +const errname = __webpack_require__(120); +const stdio = __webpack_require__(121); const TEN_MEGABYTES = 1000 * 1000 * 10; @@ -14299,21 +14026,21 @@ module.exports.shellSync = (cmd, opts) => handleShell(module.exports.sync, cmd, /***/ }), -/* 98 */ +/* 95 */ /***/ (function(module, exports) { module.exports = require("child_process"); /***/ }), -/* 99 */ +/* 96 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const cp = __webpack_require__(98); -const parse = __webpack_require__(100); -const enoent = __webpack_require__(113); +const cp = __webpack_require__(95); +const parse = __webpack_require__(97); +const enoent = __webpack_require__(110); function spawn(command, args, options) { // Parse the arguments @@ -14351,18 +14078,18 @@ module.exports._enoent = enoent; /***/ }), -/* 100 */ +/* 97 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const niceTry = __webpack_require__(101); -const resolveCommand = __webpack_require__(102); -const escape = __webpack_require__(108); -const readShebang = __webpack_require__(109); -const semver = __webpack_require__(112); +const niceTry = __webpack_require__(98); +const resolveCommand = __webpack_require__(99); +const escape = __webpack_require__(105); +const readShebang = __webpack_require__(106); +const semver = __webpack_require__(109); const isWin = process.platform === 'win32'; const isExecutableRegExp = /\.(?:com|exe)$/i; @@ -14483,7 +14210,7 @@ module.exports = parse; /***/ }), -/* 101 */ +/* 98 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -14502,15 +14229,15 @@ module.exports = function(fn) { } /***/ }), -/* 102 */ +/* 99 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const which = __webpack_require__(103); -const pathKey = __webpack_require__(107)(); +const which = __webpack_require__(100); +const pathKey = __webpack_require__(104)(); function resolveCommandAttempt(parsed, withoutPathExt) { const cwd = process.cwd(); @@ -14556,7 +14283,7 @@ module.exports = resolveCommand; /***/ }), -/* 103 */ +/* 100 */ /***/ (function(module, exports, __webpack_require__) { module.exports = which @@ -14568,7 +14295,7 @@ var isWindows = process.platform === 'win32' || var path = __webpack_require__(16) var COLON = isWindows ? ';' : ':' -var isexe = __webpack_require__(104) +var isexe = __webpack_require__(101) function getNotFoundError (cmd) { var er = new Error('not found: ' + cmd) @@ -14697,15 +14424,15 @@ function whichSync (cmd, opt) { /***/ }), -/* 104 */ +/* 101 */ /***/ (function(module, exports, __webpack_require__) { var fs = __webpack_require__(23) var core if (process.platform === 'win32' || global.TESTING_WINDOWS) { - core = __webpack_require__(105) + core = __webpack_require__(102) } else { - core = __webpack_require__(106) + core = __webpack_require__(103) } module.exports = isexe @@ -14760,7 +14487,7 @@ function sync (path, options) { /***/ }), -/* 105 */ +/* 102 */ /***/ (function(module, exports, __webpack_require__) { module.exports = isexe @@ -14808,7 +14535,7 @@ function sync (path, options) { /***/ }), -/* 106 */ +/* 103 */ /***/ (function(module, exports, __webpack_require__) { module.exports = isexe @@ -14855,7 +14582,7 @@ function checkMode (stat, options) { /***/ }), -/* 107 */ +/* 104 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -14875,7 +14602,7 @@ module.exports = opts => { /***/ }), -/* 108 */ +/* 105 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -14927,14 +14654,14 @@ module.exports.argument = escapeArgument; /***/ }), -/* 109 */ +/* 106 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const shebangCommand = __webpack_require__(110); +const shebangCommand = __webpack_require__(107); function readShebang(command) { // Read the first 150 bytes from the file @@ -14966,12 +14693,12 @@ module.exports = readShebang; /***/ }), -/* 110 */ +/* 107 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var shebangRegex = __webpack_require__(111); +var shebangRegex = __webpack_require__(108); module.exports = function (str) { var match = str.match(shebangRegex); @@ -14992,7 +14719,7 @@ module.exports = function (str) { /***/ }), -/* 111 */ +/* 108 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -15001,7 +14728,7 @@ module.exports = /^#!.*/; /***/ }), -/* 112 */ +/* 109 */ /***/ (function(module, exports) { exports = module.exports = SemVer; @@ -16331,7 +16058,7 @@ function coerce(version) { /***/ }), -/* 113 */ +/* 110 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16397,7 +16124,7 @@ module.exports = { /***/ }), -/* 114 */ +/* 111 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16419,13 +16146,13 @@ module.exports = function (x) { /***/ }), -/* 115 */ +/* 112 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathKey = __webpack_require__(116); +const pathKey = __webpack_require__(113); module.exports = opts => { opts = Object.assign({ @@ -16465,7 +16192,7 @@ module.exports.env = opts => { /***/ }), -/* 116 */ +/* 113 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16485,7 +16212,7 @@ module.exports = opts => { /***/ }), -/* 117 */ +/* 114 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16513,13 +16240,13 @@ isStream.transform = function (stream) { /***/ }), -/* 118 */ +/* 115 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pump = __webpack_require__(119); -const bufferStream = __webpack_require__(121); +const pump = __webpack_require__(116); +const bufferStream = __webpack_require__(118); class MaxBufferError extends Error { constructor() { @@ -16570,11 +16297,11 @@ module.exports.MaxBufferError = MaxBufferError; /***/ }), -/* 119 */ +/* 116 */ /***/ (function(module, exports, __webpack_require__) { var once = __webpack_require__(51) -var eos = __webpack_require__(120) +var eos = __webpack_require__(117) var fs = __webpack_require__(23) // we only need fs to get the ReadStream and WriteStream prototypes var noop = function () {} @@ -16658,7 +16385,7 @@ module.exports = pump /***/ }), -/* 120 */ +/* 117 */ /***/ (function(module, exports, __webpack_require__) { var once = __webpack_require__(51); @@ -16751,7 +16478,7 @@ module.exports = eos; /***/ }), -/* 121 */ +/* 118 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16809,7 +16536,7 @@ module.exports = options => { /***/ }), -/* 122 */ +/* 119 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16831,7 +16558,7 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 123 */ +/* 120 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16877,7 +16604,7 @@ function errname(uv, code) { /***/ }), -/* 124 */ +/* 121 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16925,7 +16652,7 @@ module.exports = opts => { /***/ }), -/* 125 */ +/* 122 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16952,7 +16679,7 @@ module.exports = isSupported ? main : fallbacks; /***/ }), -/* 126 */ +/* 123 */ /***/ (function(module, exports, __webpack_require__) { // Copyright IBM Corp. 2014,2018. All Rights Reserved. @@ -16960,12 +16687,12 @@ module.exports = isSupported ? main : fallbacks; // This file is licensed under the Apache License 2.0. // License text available at https://opensource.org/licenses/Apache-2.0 -module.exports = __webpack_require__(127); -module.exports.cli = __webpack_require__(131); +module.exports = __webpack_require__(124); +module.exports.cli = __webpack_require__(128); /***/ }), -/* 127 */ +/* 124 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16980,9 +16707,9 @@ var stream = __webpack_require__(28); var util = __webpack_require__(29); var fs = __webpack_require__(23); -var through = __webpack_require__(128); -var duplexer = __webpack_require__(129); -var StringDecoder = __webpack_require__(130).StringDecoder; +var through = __webpack_require__(125); +var duplexer = __webpack_require__(126); +var StringDecoder = __webpack_require__(127).StringDecoder; module.exports = Logger; @@ -17171,7 +16898,7 @@ function lineMerger(host) { /***/ }), -/* 128 */ +/* 125 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(28) @@ -17285,7 +17012,7 @@ function through (write, end, opts) { /***/ }), -/* 129 */ +/* 126 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(28) @@ -17378,13 +17105,13 @@ function duplex(writer, reader) { /***/ }), -/* 130 */ +/* 127 */ /***/ (function(module, exports) { module.exports = require("string_decoder"); /***/ }), -/* 131 */ +/* 128 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -17395,11 +17122,11 @@ module.exports = require("string_decoder"); -var minimist = __webpack_require__(132); +var minimist = __webpack_require__(129); var path = __webpack_require__(16); -var Logger = __webpack_require__(127); -var pkg = __webpack_require__(133); +var Logger = __webpack_require__(124); +var pkg = __webpack_require__(130); module.exports = cli; @@ -17453,7 +17180,7 @@ function usage($0, p) { /***/ }), -/* 132 */ +/* 129 */ /***/ (function(module, exports) { module.exports = function (args, opts) { @@ -17695,13 +17422,13 @@ function isNumber (x) { /***/ }), -/* 133 */ +/* 130 */ /***/ (function(module) { module.exports = {"name":"strong-log-transformer","version":"2.1.0","description":"Stream transformer that prefixes lines with timestamps and other things.","author":"Ryan Graham ","license":"Apache-2.0","repository":{"type":"git","url":"git://github.com/strongloop/strong-log-transformer"},"keywords":["logging","streams"],"bugs":{"url":"https://github.com/strongloop/strong-log-transformer/issues"},"homepage":"https://github.com/strongloop/strong-log-transformer","directories":{"test":"test"},"bin":{"sl-log-transformer":"bin/sl-log-transformer.js"},"main":"index.js","scripts":{"test":"tap --100 test/test-*"},"dependencies":{"duplexer":"^0.1.1","minimist":"^1.2.0","through":"^2.3.4"},"devDependencies":{"tap":"^12.0.1"},"engines":{"node":">=4"}}; /***/ }), -/* 134 */ +/* 131 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -17784,7 +17511,7 @@ var _path2 = _interopRequireDefault(_path); var _util = __webpack_require__(29); -var _config = __webpack_require__(135); +var _config = __webpack_require__(132); var _fs = __webpack_require__(20); @@ -17831,7 +17558,7 @@ function packagesFromGlobPattern({ pattern, rootPath }) { } /***/ }), -/* 135 */ +/* 132 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -17891,7 +17618,7 @@ function getProjectPaths(rootPath, options) { */ /***/ }), -/* 136 */ +/* 133 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -17906,11 +17633,11 @@ var _chalk = __webpack_require__(2); var _chalk2 = _interopRequireDefault(_chalk); -var _del = __webpack_require__(137); +var _del = __webpack_require__(134); var _del2 = _interopRequireDefault(_del); -var _ora = __webpack_require__(152); +var _ora = __webpack_require__(148); var _ora2 = _interopRequireDefault(_ora); @@ -18001,18 +17728,18 @@ const CleanCommand = exports.CleanCommand = { }; /***/ }), -/* 137 */ +/* 134 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const globby = __webpack_require__(138); -const isPathCwd = __webpack_require__(145); -const isPathInCwd = __webpack_require__(146); -const pify = __webpack_require__(149); -const rimraf = __webpack_require__(150); -const pMap = __webpack_require__(151); +const globby = __webpack_require__(135); +const isPathCwd = __webpack_require__(142); +const isPathInCwd = __webpack_require__(143); +const pify = __webpack_require__(62); +const rimraf = __webpack_require__(146); +const pMap = __webpack_require__(147); const rimrafP = pify(rimraf); @@ -18078,16 +17805,16 @@ module.exports.sync = (patterns, opts) => { /***/ }), -/* 138 */ +/* 135 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Promise = __webpack_require__(139); -var arrayUnion = __webpack_require__(141); -var objectAssign = __webpack_require__(143); +var Promise = __webpack_require__(136); +var arrayUnion = __webpack_require__(138); +var objectAssign = __webpack_require__(140); var glob = __webpack_require__(36); -var pify = __webpack_require__(144); +var pify = __webpack_require__(141); var globP = pify(glob, Promise).bind(glob); @@ -18173,17 +17900,17 @@ module.exports.hasMagic = function (patterns, opts) { /***/ }), -/* 139 */ +/* 136 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = typeof Promise === 'function' ? Promise : __webpack_require__(140); +module.exports = typeof Promise === 'function' ? Promise : __webpack_require__(137); /***/ }), -/* 140 */ +/* 137 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -18482,12 +18209,12 @@ module.exports = Promise; /***/ }), -/* 141 */ +/* 138 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(142); +var arrayUniq = __webpack_require__(139); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -18495,7 +18222,7 @@ module.exports = function () { /***/ }), -/* 142 */ +/* 139 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -18564,7 +18291,7 @@ if ('Set' in global) { /***/ }), -/* 143 */ +/* 140 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -18661,7 +18388,7 @@ module.exports = shouldUseNative() ? Object.assign : function (target, source) { /***/ }), -/* 144 */ +/* 141 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -18736,7 +18463,7 @@ pify.all = pify; /***/ }), -/* 145 */ +/* 142 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -18749,12 +18476,12 @@ module.exports = function (str) { /***/ }), -/* 146 */ +/* 143 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isPathInside = __webpack_require__(147); +var isPathInside = __webpack_require__(144); module.exports = function (str) { return isPathInside(str, process.cwd()); @@ -18762,13 +18489,13 @@ module.exports = function (str) { /***/ }), -/* 147 */ +/* 144 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(16); -var pathIsInside = __webpack_require__(148); +var pathIsInside = __webpack_require__(145); module.exports = function (a, b) { a = path.resolve(a); @@ -18783,7 +18510,7 @@ module.exports = function (a, b) { /***/ }), -/* 148 */ +/* 145 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -18818,98 +18545,7 @@ function stripTrailingSep(thePath) { /***/ }), -/* 149 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); - - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } - - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); - } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } - - resolve(results); - } else { - resolve(result); - } - }); - } - - fn.apply(this, args); - }); -}; - -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); - - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); - }; - - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } - - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; - } - - return ret; -}; - - -/***/ }), -/* 150 */ +/* 146 */ /***/ (function(module, exports, __webpack_require__) { module.exports = rimraf @@ -19279,7 +18915,7 @@ function rmkidsSync (p, options) { /***/ }), -/* 151 */ +/* 147 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -19353,15 +18989,15 @@ module.exports = (iterable, mapper, opts) => new Promise((resolve, reject) => { /***/ }), -/* 152 */ +/* 148 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const chalk = __webpack_require__(2); -const cliCursor = __webpack_require__(153); -const cliSpinners = __webpack_require__(157); -const logSymbols = __webpack_require__(125); +const cliCursor = __webpack_require__(149); +const cliSpinners = __webpack_require__(153); +const logSymbols = __webpack_require__(122); class Ora { constructor(options) { @@ -19508,12 +19144,12 @@ module.exports.promise = (action, options) => { /***/ }), -/* 153 */ +/* 149 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const restoreCursor = __webpack_require__(154); +const restoreCursor = __webpack_require__(150); let hidden = false; @@ -19554,13 +19190,13 @@ exports.toggle = (force, stream) => { /***/ }), -/* 154 */ +/* 150 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const onetime = __webpack_require__(155); -const signalExit = __webpack_require__(87); +const onetime = __webpack_require__(151); +const signalExit = __webpack_require__(86); module.exports = onetime(() => { signalExit(() => { @@ -19570,12 +19206,12 @@ module.exports = onetime(() => { /***/ }), -/* 155 */ +/* 151 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(156); +const mimicFn = __webpack_require__(152); module.exports = (fn, opts) => { // TODO: Remove this in v3 @@ -19616,7 +19252,7 @@ module.exports = (fn, opts) => { /***/ }), -/* 156 */ +/* 152 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -19626,26 +19262,28 @@ module.exports = (to, from) => { for (const prop of Object.getOwnPropertyNames(from).concat(Object.getOwnPropertySymbols(from))) { Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); } + + return to; }; /***/ }), -/* 157 */ +/* 153 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(158); +module.exports = __webpack_require__(154); /***/ }), -/* 158 */ +/* 154 */ /***/ (function(module) { module.exports = {"dots":{"interval":80,"frames":["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]},"dots2":{"interval":80,"frames":["⣾","⣽","⣻","⢿","⡿","⣟","⣯","⣷"]},"dots3":{"interval":80,"frames":["⠋","⠙","⠚","⠞","⠖","⠦","⠴","⠲","⠳","⠓"]},"dots4":{"interval":80,"frames":["⠄","⠆","⠇","⠋","⠙","⠸","⠰","⠠","⠰","⠸","⠙","⠋","⠇","⠆"]},"dots5":{"interval":80,"frames":["⠋","⠙","⠚","⠒","⠂","⠂","⠒","⠲","⠴","⠦","⠖","⠒","⠐","⠐","⠒","⠓","⠋"]},"dots6":{"interval":80,"frames":["⠁","⠉","⠙","⠚","⠒","⠂","⠂","⠒","⠲","⠴","⠤","⠄","⠄","⠤","⠴","⠲","⠒","⠂","⠂","⠒","⠚","⠙","⠉","⠁"]},"dots7":{"interval":80,"frames":["⠈","⠉","⠋","⠓","⠒","⠐","⠐","⠒","⠖","⠦","⠤","⠠","⠠","⠤","⠦","⠖","⠒","⠐","⠐","⠒","⠓","⠋","⠉","⠈"]},"dots8":{"interval":80,"frames":["⠁","⠁","⠉","⠙","⠚","⠒","⠂","⠂","⠒","⠲","⠴","⠤","⠄","⠄","⠤","⠠","⠠","⠤","⠦","⠖","⠒","⠐","⠐","⠒","⠓","⠋","⠉","⠈","⠈"]},"dots9":{"interval":80,"frames":["⢹","⢺","⢼","⣸","⣇","⡧","⡗","⡏"]},"dots10":{"interval":80,"frames":["⢄","⢂","⢁","⡁","⡈","⡐","⡠"]},"dots11":{"interval":100,"frames":["⠁","⠂","⠄","⡀","⢀","⠠","⠐","⠈"]},"dots12":{"interval":80,"frames":["⢀⠀","⡀⠀","⠄⠀","⢂⠀","⡂⠀","⠅⠀","⢃⠀","⡃⠀","⠍⠀","⢋⠀","⡋⠀","⠍⠁","⢋⠁","⡋⠁","⠍⠉","⠋⠉","⠋⠉","⠉⠙","⠉⠙","⠉⠩","⠈⢙","⠈⡙","⢈⠩","⡀⢙","⠄⡙","⢂⠩","⡂⢘","⠅⡘","⢃⠨","⡃⢐","⠍⡐","⢋⠠","⡋⢀","⠍⡁","⢋⠁","⡋⠁","⠍⠉","⠋⠉","⠋⠉","⠉⠙","⠉⠙","⠉⠩","⠈⢙","⠈⡙","⠈⠩","⠀⢙","⠀⡙","⠀⠩","⠀⢘","⠀⡘","⠀⠨","⠀⢐","⠀⡐","⠀⠠","⠀⢀","⠀⡀"]},"line":{"interval":130,"frames":["-","\\","|","/"]},"line2":{"interval":100,"frames":["⠂","-","–","—","–","-"]},"pipe":{"interval":100,"frames":["┤","┘","┴","└","├","┌","┬","┐"]},"simpleDots":{"interval":400,"frames":[". ",".. ","..."," "]},"simpleDotsScrolling":{"interval":200,"frames":[". ",".. ","..."," .."," ."," "]},"star":{"interval":70,"frames":["✶","✸","✹","✺","✹","✷"]},"star2":{"interval":80,"frames":["+","x","*"]},"flip":{"interval":70,"frames":["_","_","_","-","`","`","'","´","-","_","_","_"]},"hamburger":{"interval":100,"frames":["☱","☲","☴"]},"growVertical":{"interval":120,"frames":["▁","▃","▄","▅","▆","▇","▆","▅","▄","▃"]},"growHorizontal":{"interval":120,"frames":["▏","▎","▍","▌","▋","▊","▉","▊","▋","▌","▍","▎"]},"balloon":{"interval":140,"frames":[" ",".","o","O","@","*"," "]},"balloon2":{"interval":120,"frames":[".","o","O","°","O","o","."]},"noise":{"interval":100,"frames":["▓","▒","░"]},"bounce":{"interval":120,"frames":["⠁","⠂","⠄","⠂"]},"boxBounce":{"interval":120,"frames":["▖","▘","▝","▗"]},"boxBounce2":{"interval":100,"frames":["▌","▀","▐","▄"]},"triangle":{"interval":50,"frames":["◢","◣","◤","◥"]},"arc":{"interval":100,"frames":["◜","◠","◝","◞","◡","◟"]},"circle":{"interval":120,"frames":["◡","⊙","◠"]},"squareCorners":{"interval":180,"frames":["◰","◳","◲","◱"]},"circleQuarters":{"interval":120,"frames":["◴","◷","◶","◵"]},"circleHalves":{"interval":50,"frames":["◐","◓","◑","◒"]},"squish":{"interval":100,"frames":["╫","╪"]},"toggle":{"interval":250,"frames":["⊶","⊷"]},"toggle2":{"interval":80,"frames":["▫","▪"]},"toggle3":{"interval":120,"frames":["□","■"]},"toggle4":{"interval":100,"frames":["■","□","▪","▫"]},"toggle5":{"interval":100,"frames":["▮","▯"]},"toggle6":{"interval":300,"frames":["ဝ","၀"]},"toggle7":{"interval":80,"frames":["⦾","⦿"]},"toggle8":{"interval":100,"frames":["◍","◌"]},"toggle9":{"interval":100,"frames":["◉","◎"]},"toggle10":{"interval":100,"frames":["㊂","㊀","㊁"]},"toggle11":{"interval":50,"frames":["⧇","⧆"]},"toggle12":{"interval":120,"frames":["☗","☖"]},"toggle13":{"interval":80,"frames":["=","*","-"]},"arrow":{"interval":100,"frames":["←","↖","↑","↗","→","↘","↓","↙"]},"arrow2":{"interval":80,"frames":["⬆️ ","↗️ ","➡️ ","↘️ ","⬇️ ","↙️ ","⬅️ ","↖️ "]},"arrow3":{"interval":120,"frames":["▹▹▹▹▹","▸▹▹▹▹","▹▸▹▹▹","▹▹▸▹▹","▹▹▹▸▹","▹▹▹▹▸"]},"bouncingBar":{"interval":80,"frames":["[ ]","[= ]","[== ]","[=== ]","[ ===]","[ ==]","[ =]","[ ]","[ =]","[ ==]","[ ===]","[====]","[=== ]","[== ]","[= ]"]},"bouncingBall":{"interval":80,"frames":["( ● )","( ● )","( ● )","( ● )","( ●)","( ● )","( ● )","( ● )","( ● )","(● )"]},"smiley":{"interval":200,"frames":["😄 ","😝 "]},"monkey":{"interval":300,"frames":["🙈 ","🙈 ","🙉 ","🙊 "]},"hearts":{"interval":100,"frames":["💛 ","💙 ","💜 ","💚 ","❤️ "]},"clock":{"interval":100,"frames":["🕐 ","🕑 ","🕒 ","🕓 ","🕔 ","🕕 ","🕖 ","🕗 ","🕘 ","🕙 ","🕚 "]},"earth":{"interval":180,"frames":["🌍 ","🌎 ","🌏 "]},"moon":{"interval":80,"frames":["🌑 ","🌒 ","🌓 ","🌔 ","🌕 ","🌖 ","🌗 ","🌘 "]},"runner":{"interval":140,"frames":["🚶 ","🏃 "]},"pong":{"interval":80,"frames":["▐⠂ ▌","▐⠈ ▌","▐ ⠂ ▌","▐ ⠠ ▌","▐ ⡀ ▌","▐ ⠠ ▌","▐ ⠂ ▌","▐ ⠈ ▌","▐ ⠂ ▌","▐ ⠠ ▌","▐ ⡀ ▌","▐ ⠠ ▌","▐ ⠂ ▌","▐ ⠈ ▌","▐ ⠂▌","▐ ⠠▌","▐ ⡀▌","▐ ⠠ ▌","▐ ⠂ ▌","▐ ⠈ ▌","▐ ⠂ ▌","▐ ⠠ ▌","▐ ⡀ ▌","▐ ⠠ ▌","▐ ⠂ ▌","▐ ⠈ ▌","▐ ⠂ ▌","▐ ⠠ ▌","▐ ⡀ ▌","▐⠠ ▌"]},"shark":{"interval":120,"frames":["▐|\\____________▌","▐_|\\___________▌","▐__|\\__________▌","▐___|\\_________▌","▐____|\\________▌","▐_____|\\_______▌","▐______|\\______▌","▐_______|\\_____▌","▐________|\\____▌","▐_________|\\___▌","▐__________|\\__▌","▐___________|\\_▌","▐____________|\\▌","▐____________/|▌","▐___________/|_▌","▐__________/|__▌","▐_________/|___▌","▐________/|____▌","▐_______/|_____▌","▐______/|______▌","▐_____/|_______▌","▐____/|________▌","▐___/|_________▌","▐__/|__________▌","▐_/|___________▌","▐/|____________▌"]},"dqpb":{"interval":100,"frames":["d","q","p","b"]},"weather":{"interval":100,"frames":["☀️ ","☀️ ","☀️ ","🌤 ","⛅️ ","🌥 ","☁️ ","🌧 ","🌨 ","🌧 ","🌨 ","🌧 ","🌨 ","⛈ ","🌨 ","🌧 ","🌨 ","☁️ ","🌥 ","⛅️ ","🌤 ","☀️ ","☀️ "]},"christmas":{"interval":400,"frames":["🌲","🎄"]}}; /***/ }), -/* 159 */ +/* 155 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -19717,7 +19355,7 @@ const RunCommand = exports.RunCommand = { }; /***/ }), -/* 160 */ +/* 156 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -19738,7 +19376,7 @@ var _parallelize = __webpack_require__(34); var _projects = __webpack_require__(35); -var _watch = __webpack_require__(161); +var _watch = __webpack_require__(157); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -19820,7 +19458,7 @@ const WatchCommand = exports.WatchCommand = { }; /***/ }), -/* 161 */ +/* 157 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -19831,11 +19469,11 @@ Object.defineProperty(exports, "__esModule", { }); exports.waitUntilWatchIsReady = waitUntilWatchIsReady; -var _rxjs = __webpack_require__(162); +var _rxjs = __webpack_require__(158); var Rx = _interopRequireWildcard(_rxjs); -var _operators = __webpack_require__(261); +var _operators = __webpack_require__(257); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } @@ -19889,168 +19527,168 @@ function waitUntilWatchIsReady(stream, opts = {}) { } /***/ }), -/* 162 */ +/* 158 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _internal_Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); +/* harmony import */ var _internal_Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Observable", function() { return _internal_Observable__WEBPACK_IMPORTED_MODULE_0__["Observable"]; }); -/* harmony import */ var _internal_observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(181); +/* harmony import */ var _internal_observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(177); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ConnectableObservable", function() { return _internal_observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_1__["ConnectableObservable"]; }); -/* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(186); +/* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(182); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GroupedObservable", function() { return _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_2__["GroupedObservable"]; }); -/* harmony import */ var _internal_symbol_observable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(178); +/* harmony import */ var _internal_symbol_observable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(174); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "observable", function() { return _internal_symbol_observable__WEBPACK_IMPORTED_MODULE_3__["observable"]; }); -/* harmony import */ var _internal_Subject__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(182); +/* harmony import */ var _internal_Subject__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(178); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Subject", function() { return _internal_Subject__WEBPACK_IMPORTED_MODULE_4__["Subject"]; }); -/* harmony import */ var _internal_BehaviorSubject__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(187); +/* harmony import */ var _internal_BehaviorSubject__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(183); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "BehaviorSubject", function() { return _internal_BehaviorSubject__WEBPACK_IMPORTED_MODULE_5__["BehaviorSubject"]; }); -/* harmony import */ var _internal_ReplaySubject__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(188); +/* harmony import */ var _internal_ReplaySubject__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(184); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ReplaySubject", function() { return _internal_ReplaySubject__WEBPACK_IMPORTED_MODULE_6__["ReplaySubject"]; }); -/* harmony import */ var _internal_AsyncSubject__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(205); +/* harmony import */ var _internal_AsyncSubject__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(201); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "AsyncSubject", function() { return _internal_AsyncSubject__WEBPACK_IMPORTED_MODULE_7__["AsyncSubject"]; }); -/* harmony import */ var _internal_scheduler_asap__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(206); +/* harmony import */ var _internal_scheduler_asap__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(202); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "asapScheduler", function() { return _internal_scheduler_asap__WEBPACK_IMPORTED_MODULE_8__["asap"]; }); -/* harmony import */ var _internal_scheduler_async__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(210); +/* harmony import */ var _internal_scheduler_async__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(206); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "asyncScheduler", function() { return _internal_scheduler_async__WEBPACK_IMPORTED_MODULE_9__["async"]; }); -/* harmony import */ var _internal_scheduler_queue__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(189); +/* harmony import */ var _internal_scheduler_queue__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(185); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "queueScheduler", function() { return _internal_scheduler_queue__WEBPACK_IMPORTED_MODULE_10__["queue"]; }); -/* harmony import */ var _internal_scheduler_animationFrame__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(211); +/* harmony import */ var _internal_scheduler_animationFrame__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(207); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "animationFrameScheduler", function() { return _internal_scheduler_animationFrame__WEBPACK_IMPORTED_MODULE_11__["animationFrame"]; }); -/* harmony import */ var _internal_scheduler_VirtualTimeScheduler__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(214); +/* harmony import */ var _internal_scheduler_VirtualTimeScheduler__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(210); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "VirtualTimeScheduler", function() { return _internal_scheduler_VirtualTimeScheduler__WEBPACK_IMPORTED_MODULE_12__["VirtualTimeScheduler"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "VirtualAction", function() { return _internal_scheduler_VirtualTimeScheduler__WEBPACK_IMPORTED_MODULE_12__["VirtualAction"]; }); -/* harmony import */ var _internal_Scheduler__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(195); +/* harmony import */ var _internal_Scheduler__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(191); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Scheduler", function() { return _internal_Scheduler__WEBPACK_IMPORTED_MODULE_13__["Scheduler"]; }); -/* harmony import */ var _internal_Subscription__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(171); +/* harmony import */ var _internal_Subscription__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(167); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Subscription", function() { return _internal_Subscription__WEBPACK_IMPORTED_MODULE_14__["Subscription"]; }); -/* harmony import */ var _internal_Subscriber__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(165); +/* harmony import */ var _internal_Subscriber__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(161); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Subscriber", function() { return _internal_Subscriber__WEBPACK_IMPORTED_MODULE_15__["Subscriber"]; }); -/* harmony import */ var _internal_Notification__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(197); +/* harmony import */ var _internal_Notification__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(193); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Notification", function() { return _internal_Notification__WEBPACK_IMPORTED_MODULE_16__["Notification"]; }); -/* harmony import */ var _internal_util_pipe__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(179); +/* harmony import */ var _internal_util_pipe__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(175); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pipe", function() { return _internal_util_pipe__WEBPACK_IMPORTED_MODULE_17__["pipe"]; }); -/* harmony import */ var _internal_util_noop__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(180); +/* harmony import */ var _internal_util_noop__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(176); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "noop", function() { return _internal_util_noop__WEBPACK_IMPORTED_MODULE_18__["noop"]; }); -/* harmony import */ var _internal_util_identity__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(215); +/* harmony import */ var _internal_util_identity__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(211); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "identity", function() { return _internal_util_identity__WEBPACK_IMPORTED_MODULE_19__["identity"]; }); -/* harmony import */ var _internal_util_isObservable__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(216); +/* harmony import */ var _internal_util_isObservable__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(212); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isObservable", function() { return _internal_util_isObservable__WEBPACK_IMPORTED_MODULE_20__["isObservable"]; }); -/* harmony import */ var _internal_util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(217); +/* harmony import */ var _internal_util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(213); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ArgumentOutOfRangeError", function() { return _internal_util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_21__["ArgumentOutOfRangeError"]; }); -/* harmony import */ var _internal_util_EmptyError__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(218); +/* harmony import */ var _internal_util_EmptyError__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(214); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "EmptyError", function() { return _internal_util_EmptyError__WEBPACK_IMPORTED_MODULE_22__["EmptyError"]; }); -/* harmony import */ var _internal_util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(183); +/* harmony import */ var _internal_util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(179); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ObjectUnsubscribedError", function() { return _internal_util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_23__["ObjectUnsubscribedError"]; }); -/* harmony import */ var _internal_util_UnsubscriptionError__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(176); +/* harmony import */ var _internal_util_UnsubscriptionError__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(172); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "UnsubscriptionError", function() { return _internal_util_UnsubscriptionError__WEBPACK_IMPORTED_MODULE_24__["UnsubscriptionError"]; }); -/* harmony import */ var _internal_util_TimeoutError__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(219); +/* harmony import */ var _internal_util_TimeoutError__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(215); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "TimeoutError", function() { return _internal_util_TimeoutError__WEBPACK_IMPORTED_MODULE_25__["TimeoutError"]; }); -/* harmony import */ var _internal_observable_bindCallback__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(220); +/* harmony import */ var _internal_observable_bindCallback__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(216); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bindCallback", function() { return _internal_observable_bindCallback__WEBPACK_IMPORTED_MODULE_26__["bindCallback"]; }); -/* harmony import */ var _internal_observable_bindNodeCallback__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(222); +/* harmony import */ var _internal_observable_bindNodeCallback__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(218); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bindNodeCallback", function() { return _internal_observable_bindNodeCallback__WEBPACK_IMPORTED_MODULE_27__["bindNodeCallback"]; }); -/* harmony import */ var _internal_observable_combineLatest__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(223); +/* harmony import */ var _internal_observable_combineLatest__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(219); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return _internal_observable_combineLatest__WEBPACK_IMPORTED_MODULE_28__["combineLatest"]; }); -/* harmony import */ var _internal_observable_concat__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(234); +/* harmony import */ var _internal_observable_concat__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(230); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return _internal_observable_concat__WEBPACK_IMPORTED_MODULE_29__["concat"]; }); -/* harmony import */ var _internal_observable_defer__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(244); +/* harmony import */ var _internal_observable_defer__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(240); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "defer", function() { return _internal_observable_defer__WEBPACK_IMPORTED_MODULE_30__["defer"]; }); -/* harmony import */ var _internal_observable_empty__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(198); +/* harmony import */ var _internal_observable_empty__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(194); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "empty", function() { return _internal_observable_empty__WEBPACK_IMPORTED_MODULE_31__["empty"]; }); -/* harmony import */ var _internal_observable_forkJoin__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(245); +/* harmony import */ var _internal_observable_forkJoin__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(241); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "forkJoin", function() { return _internal_observable_forkJoin__WEBPACK_IMPORTED_MODULE_32__["forkJoin"]; }); -/* harmony import */ var _internal_observable_from__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(235); +/* harmony import */ var _internal_observable_from__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(231); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "from", function() { return _internal_observable_from__WEBPACK_IMPORTED_MODULE_33__["from"]; }); -/* harmony import */ var _internal_observable_fromEvent__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(246); +/* harmony import */ var _internal_observable_fromEvent__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(242); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "fromEvent", function() { return _internal_observable_fromEvent__WEBPACK_IMPORTED_MODULE_34__["fromEvent"]; }); -/* harmony import */ var _internal_observable_fromEventPattern__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(247); +/* harmony import */ var _internal_observable_fromEventPattern__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(243); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "fromEventPattern", function() { return _internal_observable_fromEventPattern__WEBPACK_IMPORTED_MODULE_35__["fromEventPattern"]; }); -/* harmony import */ var _internal_observable_generate__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(248); +/* harmony import */ var _internal_observable_generate__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(244); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "generate", function() { return _internal_observable_generate__WEBPACK_IMPORTED_MODULE_36__["generate"]; }); -/* harmony import */ var _internal_observable_iif__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(249); +/* harmony import */ var _internal_observable_iif__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(245); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "iif", function() { return _internal_observable_iif__WEBPACK_IMPORTED_MODULE_37__["iif"]; }); -/* harmony import */ var _internal_observable_interval__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(250); +/* harmony import */ var _internal_observable_interval__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(246); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "interval", function() { return _internal_observable_interval__WEBPACK_IMPORTED_MODULE_38__["interval"]; }); -/* harmony import */ var _internal_observable_merge__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(252); +/* harmony import */ var _internal_observable_merge__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(248); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return _internal_observable_merge__WEBPACK_IMPORTED_MODULE_39__["merge"]; }); -/* harmony import */ var _internal_observable_never__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(253); +/* harmony import */ var _internal_observable_never__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(249); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "never", function() { return _internal_observable_never__WEBPACK_IMPORTED_MODULE_40__["never"]; }); -/* harmony import */ var _internal_observable_of__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(199); +/* harmony import */ var _internal_observable_of__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(195); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "of", function() { return _internal_observable_of__WEBPACK_IMPORTED_MODULE_41__["of"]; }); -/* harmony import */ var _internal_observable_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(254); +/* harmony import */ var _internal_observable_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(250); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return _internal_observable_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_42__["onErrorResumeNext"]; }); -/* harmony import */ var _internal_observable_pairs__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(255); +/* harmony import */ var _internal_observable_pairs__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(251); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pairs", function() { return _internal_observable_pairs__WEBPACK_IMPORTED_MODULE_43__["pairs"]; }); -/* harmony import */ var _internal_observable_race__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(256); +/* harmony import */ var _internal_observable_race__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(252); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "race", function() { return _internal_observable_race__WEBPACK_IMPORTED_MODULE_44__["race"]; }); -/* harmony import */ var _internal_observable_range__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(257); +/* harmony import */ var _internal_observable_range__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(253); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "range", function() { return _internal_observable_range__WEBPACK_IMPORTED_MODULE_45__["range"]; }); -/* harmony import */ var _internal_observable_throwError__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(204); +/* harmony import */ var _internal_observable_throwError__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(200); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwError", function() { return _internal_observable_throwError__WEBPACK_IMPORTED_MODULE_46__["throwError"]; }); -/* harmony import */ var _internal_observable_timer__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(258); +/* harmony import */ var _internal_observable_timer__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(254); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timer", function() { return _internal_observable_timer__WEBPACK_IMPORTED_MODULE_47__["timer"]; }); -/* harmony import */ var _internal_observable_using__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(259); +/* harmony import */ var _internal_observable_using__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(255); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "using", function() { return _internal_observable_using__WEBPACK_IMPORTED_MODULE_48__["using"]; }); -/* harmony import */ var _internal_observable_zip__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(260); +/* harmony import */ var _internal_observable_zip__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(256); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return _internal_observable_zip__WEBPACK_IMPORTED_MODULE_49__["zip"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "EMPTY", function() { return _internal_observable_empty__WEBPACK_IMPORTED_MODULE_31__["EMPTY"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "NEVER", function() { return _internal_observable_never__WEBPACK_IMPORTED_MODULE_40__["NEVER"]; }); -/* harmony import */ var _internal_config__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(169); +/* harmony import */ var _internal_config__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(165); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "config", function() { return _internal_config__WEBPACK_IMPORTED_MODULE_50__["config"]; }); /** PURE_IMPORTS_START PURE_IMPORTS_END */ @@ -20111,16 +19749,16 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 163 */ +/* 159 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Observable", function() { return Observable; }); -/* harmony import */ var _util_toSubscriber__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(164); -/* harmony import */ var _internal_symbol_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); -/* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(179); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(169); +/* harmony import */ var _util_toSubscriber__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(160); +/* harmony import */ var _internal_symbol_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(174); +/* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(175); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(165); /** PURE_IMPORTS_START _util_toSubscriber,_internal_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */ @@ -20234,15 +19872,15 @@ function getPromiseCtor(promiseCtor) { /***/ }), -/* 164 */ +/* 160 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toSubscriber", function() { return toSubscriber; }); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(165); -/* harmony import */ var _symbol_rxSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(177); -/* harmony import */ var _Observer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(168); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(161); +/* harmony import */ var _symbol_rxSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(173); +/* harmony import */ var _Observer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(164); /** PURE_IMPORTS_START _Subscriber,_symbol_rxSubscriber,_Observer PURE_IMPORTS_END */ @@ -20265,19 +19903,19 @@ function toSubscriber(nextOrObserver, error, complete) { /***/ }), -/* 165 */ +/* 161 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Subscriber", function() { return Subscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); -/* harmony import */ var _Observer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(168); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); -/* harmony import */ var _internal_symbol_rxSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(177); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(169); -/* harmony import */ var _util_hostReportError__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(170); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(163); +/* harmony import */ var _Observer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(164); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(167); +/* harmony import */ var _internal_symbol_rxSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(173); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(165); +/* harmony import */ var _util_hostReportError__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(166); /** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */ @@ -20519,7 +20157,7 @@ function isTrustedSubscriber(obj) { /***/ }), -/* 166 */ +/* 162 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -20732,7 +20370,7 @@ function __importDefault(mod) { /***/ }), -/* 167 */ +/* 163 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -20746,14 +20384,14 @@ function isFunction(x) { /***/ }), -/* 168 */ +/* 164 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "empty", function() { return empty; }); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(169); -/* harmony import */ var _util_hostReportError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(170); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(165); +/* harmony import */ var _util_hostReportError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(166); /** PURE_IMPORTS_START _config,_util_hostReportError PURE_IMPORTS_END */ @@ -20774,7 +20412,7 @@ var empty = { /***/ }), -/* 169 */ +/* 165 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -20802,7 +20440,7 @@ var config = { /***/ }), -/* 170 */ +/* 166 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -20816,18 +20454,18 @@ function hostReportError(err) { /***/ }), -/* 171 */ +/* 167 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Subscription", function() { return Subscription; }); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(172); -/* harmony import */ var _util_isObject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(173); -/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(167); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(175); -/* harmony import */ var _util_UnsubscriptionError__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(176); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(168); +/* harmony import */ var _util_isObject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(169); +/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(163); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(171); +/* harmony import */ var _util_UnsubscriptionError__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(172); /** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_tryCatch,_util_errorObject,_util_UnsubscriptionError PURE_IMPORTS_END */ @@ -20963,7 +20601,7 @@ function flattenUnsubscriptionErrors(errors) { /***/ }), -/* 172 */ +/* 168 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -20975,7 +20613,7 @@ var isArray = Array.isArray || (function (x) { return x && typeof x.length === ' /***/ }), -/* 173 */ +/* 169 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -20989,13 +20627,13 @@ function isObject(x) { /***/ }), -/* 174 */ +/* 170 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "tryCatch", function() { return tryCatch; }); -/* harmony import */ var _errorObject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(175); +/* harmony import */ var _errorObject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(171); /** PURE_IMPORTS_START _errorObject PURE_IMPORTS_END */ var tryCatchTarget; @@ -21016,7 +20654,7 @@ function tryCatch(fn) { /***/ }), -/* 175 */ +/* 171 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -21028,13 +20666,13 @@ var errorObject = { e: {} }; /***/ }), -/* 176 */ +/* 172 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsubscriptionError", function() { return UnsubscriptionError; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); /** PURE_IMPORTS_START tslib PURE_IMPORTS_END */ var UnsubscriptionError = /*@__PURE__*/ (function (_super) { @@ -21054,7 +20692,7 @@ var UnsubscriptionError = /*@__PURE__*/ (function (_super) { /***/ }), -/* 177 */ +/* 173 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -21070,7 +20708,7 @@ var $$rxSubscriber = rxSubscriber; /***/ }), -/* 178 */ +/* 174 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -21082,14 +20720,14 @@ var observable = typeof Symbol === 'function' && Symbol.observable || '@@observa /***/ }), -/* 179 */ +/* 175 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pipe", function() { return pipe; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pipeFromArray", function() { return pipeFromArray; }); -/* harmony import */ var _noop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(180); +/* harmony import */ var _noop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(176); /** PURE_IMPORTS_START _noop PURE_IMPORTS_END */ function pipe() { @@ -21114,7 +20752,7 @@ function pipeFromArray(fns) { /***/ }), -/* 180 */ +/* 176 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -21126,19 +20764,19 @@ function noop() { } /***/ }), -/* 181 */ +/* 177 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConnectableObservable", function() { return ConnectableObservable; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "connectableObservableDescriptor", function() { return connectableObservableDescriptor; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(163); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(165); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(171); -/* harmony import */ var _operators_refCount__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(185); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(159); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(161); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(167); +/* harmony import */ var _operators_refCount__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(181); /** PURE_IMPORTS_START tslib,_Subject,_Observable,_Subscriber,_Subscription,_operators_refCount PURE_IMPORTS_END */ @@ -21285,7 +20923,7 @@ var RefCountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 182 */ +/* 178 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -21293,13 +20931,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubjectSubscriber", function() { return SubjectSubscriber; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Subject", function() { return Subject; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnonymousSubject", function() { return AnonymousSubject; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(163); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(165); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); -/* harmony import */ var _util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(183); -/* harmony import */ var _SubjectSubscription__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(184); -/* harmony import */ var _internal_symbol_rxSubscriber__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(177); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(159); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(161); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(167); +/* harmony import */ var _util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(179); +/* harmony import */ var _SubjectSubscription__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(180); +/* harmony import */ var _internal_symbol_rxSubscriber__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(173); /** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */ @@ -21461,13 +21099,13 @@ var AnonymousSubject = /*@__PURE__*/ (function (_super) { /***/ }), -/* 183 */ +/* 179 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObjectUnsubscribedError", function() { return ObjectUnsubscribedError; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); /** PURE_IMPORTS_START tslib PURE_IMPORTS_END */ var ObjectUnsubscribedError = /*@__PURE__*/ (function (_super) { @@ -21485,14 +21123,14 @@ var ObjectUnsubscribedError = /*@__PURE__*/ (function (_super) { /***/ }), -/* 184 */ +/* 180 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubjectSubscription", function() { return SubjectSubscription; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); /** PURE_IMPORTS_START tslib,_Subscription PURE_IMPORTS_END */ @@ -21528,14 +21166,14 @@ var SubjectSubscription = /*@__PURE__*/ (function (_super) { /***/ }), -/* 185 */ +/* 181 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "refCount", function() { return refCount; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -21597,18 +21235,18 @@ var RefCountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 186 */ +/* 182 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "groupBy", function() { return groupBy; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GroupedObservable", function() { return GroupedObservable; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(171); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(163); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(182); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(167); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(159); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(178); /** PURE_IMPORTS_START tslib,_Subscriber,_Subscription,_Observable,_Subject PURE_IMPORTS_END */ @@ -21794,15 +21432,15 @@ var InnerRefCountSubscription = /*@__PURE__*/ (function (_super) { /***/ }), -/* 187 */ +/* 183 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BehaviorSubject", function() { return BehaviorSubject; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(183); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(179); /** PURE_IMPORTS_START tslib,_Subject,_util_ObjectUnsubscribedError PURE_IMPORTS_END */ @@ -21849,19 +21487,19 @@ var BehaviorSubject = /*@__PURE__*/ (function (_super) { /***/ }), -/* 188 */ +/* 184 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReplaySubject", function() { return ReplaySubject; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _scheduler_queue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(189); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); -/* harmony import */ var _operators_observeOn__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(196); -/* harmony import */ var _util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(183); -/* harmony import */ var _SubjectSubscription__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(184); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _scheduler_queue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(185); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(167); +/* harmony import */ var _operators_observeOn__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(192); +/* harmony import */ var _util_ObjectUnsubscribedError__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(179); +/* harmony import */ var _SubjectSubscription__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(180); /** PURE_IMPORTS_START tslib,_Subject,_scheduler_queue,_Subscription,_operators_observeOn,_util_ObjectUnsubscribedError,_SubjectSubscription PURE_IMPORTS_END */ @@ -21982,14 +21620,14 @@ var ReplayEvent = /*@__PURE__*/ (function () { /***/ }), -/* 189 */ +/* 185 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "queue", function() { return queue; }); -/* harmony import */ var _QueueAction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(190); -/* harmony import */ var _QueueScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(193); +/* harmony import */ var _QueueAction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(186); +/* harmony import */ var _QueueScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(189); /** PURE_IMPORTS_START _QueueAction,_QueueScheduler PURE_IMPORTS_END */ @@ -21998,14 +21636,14 @@ var queue = /*@__PURE__*/ new _QueueScheduler__WEBPACK_IMPORTED_MODULE_1__["Queu /***/ }), -/* 190 */ +/* 186 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QueueAction", function() { return QueueAction; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(191); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(187); /** PURE_IMPORTS_START tslib,_AsyncAction PURE_IMPORTS_END */ @@ -22050,14 +21688,14 @@ var QueueAction = /*@__PURE__*/ (function (_super) { /***/ }), -/* 191 */ +/* 187 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AsyncAction", function() { return AsyncAction; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Action__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(192); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Action__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(188); /** PURE_IMPORTS_START tslib,_Action PURE_IMPORTS_END */ @@ -22155,14 +21793,14 @@ var AsyncAction = /*@__PURE__*/ (function (_super) { /***/ }), -/* 192 */ +/* 188 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Action", function() { return Action; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); /** PURE_IMPORTS_START tslib,_Subscription PURE_IMPORTS_END */ @@ -22184,14 +21822,14 @@ var Action = /*@__PURE__*/ (function (_super) { /***/ }), -/* 193 */ +/* 189 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QueueScheduler", function() { return QueueScheduler; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(194); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(190); /** PURE_IMPORTS_START tslib,_AsyncScheduler PURE_IMPORTS_END */ @@ -22207,14 +21845,14 @@ var QueueScheduler = /*@__PURE__*/ (function (_super) { /***/ }), -/* 194 */ +/* 190 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AsyncScheduler", function() { return AsyncScheduler; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Scheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(195); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Scheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(191); /** PURE_IMPORTS_START tslib,_Scheduler PURE_IMPORTS_END */ @@ -22276,7 +21914,7 @@ var AsyncScheduler = /*@__PURE__*/ (function (_super) { /***/ }), -/* 195 */ +/* 191 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -22304,7 +21942,7 @@ var Scheduler = /*@__PURE__*/ (function () { /***/ }), -/* 196 */ +/* 192 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -22313,9 +21951,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObserveOnOperator", function() { return ObserveOnOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObserveOnSubscriber", function() { return ObserveOnSubscriber; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObserveOnMessage", function() { return ObserveOnMessage; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(197); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(193); /** PURE_IMPORTS_START tslib,_Subscriber,_Notification PURE_IMPORTS_END */ @@ -22385,15 +22023,15 @@ var ObserveOnMessage = /*@__PURE__*/ (function () { /***/ }), -/* 197 */ +/* 193 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Notification", function() { return Notification; }); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(198); -/* harmony import */ var _observable_of__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(199); -/* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(204); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(194); +/* harmony import */ var _observable_of__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(195); +/* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(200); /** PURE_IMPORTS_START _observable_empty,_observable_of,_observable_throwError PURE_IMPORTS_END */ @@ -22467,7 +22105,7 @@ var Notification = /*@__PURE__*/ (function () { /***/ }), -/* 198 */ +/* 194 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -22475,7 +22113,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EMPTY", function() { return EMPTY; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "empty", function() { return empty; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "emptyScheduled", function() { return emptyScheduled; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */ var EMPTY = /*@__PURE__*/ new _Observable__WEBPACK_IMPORTED_MODULE_0__["Observable"](function (subscriber) { return subscriber.complete(); }); @@ -22489,16 +22127,16 @@ function emptyScheduled(scheduler) { /***/ }), -/* 199 */ +/* 195 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "of", function() { return of; }); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(200); -/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(201); -/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(198); -/* harmony import */ var _scalar__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(203); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(196); +/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(197); +/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(194); +/* harmony import */ var _scalar__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(199); /** PURE_IMPORTS_START _util_isScheduler,_fromArray,_empty,_scalar PURE_IMPORTS_END */ @@ -22529,7 +22167,7 @@ function of() { /***/ }), -/* 200 */ +/* 196 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -22543,15 +22181,15 @@ function isScheduler(value) { /***/ }), -/* 201 */ +/* 197 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromArray", function() { return fromArray; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); -/* harmony import */ var _util_subscribeToArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(202); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); +/* harmony import */ var _util_subscribeToArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(198); /** PURE_IMPORTS_START _Observable,_Subscription,_util_subscribeToArray PURE_IMPORTS_END */ @@ -22582,7 +22220,7 @@ function fromArray(input, scheduler) { /***/ }), -/* 202 */ +/* 198 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -22603,13 +22241,13 @@ var subscribeToArray = function (array) { /***/ }), -/* 203 */ +/* 199 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scalar", function() { return scalar; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */ function scalar(value) { @@ -22625,13 +22263,13 @@ function scalar(value) { /***/ }), -/* 204 */ +/* 200 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throwError", function() { return throwError; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */ function throwError(error, scheduler) { @@ -22650,15 +22288,15 @@ function dispatch(_a) { /***/ }), -/* 205 */ +/* 201 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AsyncSubject", function() { return AsyncSubject; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(171); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(167); /** PURE_IMPORTS_START tslib,_Subject,_Subscription PURE_IMPORTS_END */ @@ -22709,14 +22347,14 @@ var AsyncSubject = /*@__PURE__*/ (function (_super) { /***/ }), -/* 206 */ +/* 202 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "asap", function() { return asap; }); -/* harmony import */ var _AsapAction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(207); -/* harmony import */ var _AsapScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(209); +/* harmony import */ var _AsapAction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(203); +/* harmony import */ var _AsapScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(205); /** PURE_IMPORTS_START _AsapAction,_AsapScheduler PURE_IMPORTS_END */ @@ -22725,15 +22363,15 @@ var asap = /*@__PURE__*/ new _AsapScheduler__WEBPACK_IMPORTED_MODULE_1__["AsapSc /***/ }), -/* 207 */ +/* 203 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AsapAction", function() { return AsapAction; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _util_Immediate__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(208); -/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(191); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _util_Immediate__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(204); +/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(187); /** PURE_IMPORTS_START tslib,_util_Immediate,_AsyncAction PURE_IMPORTS_END */ @@ -22776,7 +22414,7 @@ var AsapAction = /*@__PURE__*/ (function (_super) { /***/ }), -/* 208 */ +/* 204 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -22806,14 +22444,14 @@ var Immediate = { /***/ }), -/* 209 */ +/* 205 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AsapScheduler", function() { return AsapScheduler; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(194); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(190); /** PURE_IMPORTS_START tslib,_AsyncScheduler PURE_IMPORTS_END */ @@ -22850,14 +22488,14 @@ var AsapScheduler = /*@__PURE__*/ (function (_super) { /***/ }), -/* 210 */ +/* 206 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "async", function() { return async; }); -/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(191); -/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(194); +/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(187); +/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(190); /** PURE_IMPORTS_START _AsyncAction,_AsyncScheduler PURE_IMPORTS_END */ @@ -22866,14 +22504,14 @@ var async = /*@__PURE__*/ new _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__["Asyn /***/ }), -/* 211 */ +/* 207 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "animationFrame", function() { return animationFrame; }); -/* harmony import */ var _AnimationFrameAction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(212); -/* harmony import */ var _AnimationFrameScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(213); +/* harmony import */ var _AnimationFrameAction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(208); +/* harmony import */ var _AnimationFrameScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(209); /** PURE_IMPORTS_START _AnimationFrameAction,_AnimationFrameScheduler PURE_IMPORTS_END */ @@ -22882,14 +22520,14 @@ var animationFrame = /*@__PURE__*/ new _AnimationFrameScheduler__WEBPACK_IMPORTE /***/ }), -/* 212 */ +/* 208 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationFrameAction", function() { return AnimationFrameAction; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(191); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(187); /** PURE_IMPORTS_START tslib,_AsyncAction PURE_IMPORTS_END */ @@ -22931,14 +22569,14 @@ var AnimationFrameAction = /*@__PURE__*/ (function (_super) { /***/ }), -/* 213 */ +/* 209 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationFrameScheduler", function() { return AnimationFrameScheduler; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(194); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(190); /** PURE_IMPORTS_START tslib,_AsyncScheduler PURE_IMPORTS_END */ @@ -22975,16 +22613,16 @@ var AnimationFrameScheduler = /*@__PURE__*/ (function (_super) { /***/ }), -/* 214 */ +/* 210 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualTimeScheduler", function() { return VirtualTimeScheduler; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualAction", function() { return VirtualAction; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(191); -/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(194); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _AsyncAction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(187); +/* harmony import */ var _AsyncScheduler__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(190); /** PURE_IMPORTS_START tslib,_AsyncAction,_AsyncScheduler PURE_IMPORTS_END */ @@ -23096,7 +22734,7 @@ var VirtualAction = /*@__PURE__*/ (function (_super) { /***/ }), -/* 215 */ +/* 211 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -23110,13 +22748,13 @@ function identity(x) { /***/ }), -/* 216 */ +/* 212 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isObservable", function() { return isObservable; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */ function isObservable(obj) { @@ -23126,13 +22764,13 @@ function isObservable(obj) { /***/ }), -/* 217 */ +/* 213 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArgumentOutOfRangeError", function() { return ArgumentOutOfRangeError; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); /** PURE_IMPORTS_START tslib PURE_IMPORTS_END */ var ArgumentOutOfRangeError = /*@__PURE__*/ (function (_super) { @@ -23150,13 +22788,13 @@ var ArgumentOutOfRangeError = /*@__PURE__*/ (function (_super) { /***/ }), -/* 218 */ +/* 214 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EmptyError", function() { return EmptyError; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); /** PURE_IMPORTS_START tslib PURE_IMPORTS_END */ var EmptyError = /*@__PURE__*/ (function (_super) { @@ -23174,13 +22812,13 @@ var EmptyError = /*@__PURE__*/ (function (_super) { /***/ }), -/* 219 */ +/* 215 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TimeoutError", function() { return TimeoutError; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); /** PURE_IMPORTS_START tslib PURE_IMPORTS_END */ var TimeoutError = /*@__PURE__*/ (function (_super) { @@ -23198,17 +22836,17 @@ var TimeoutError = /*@__PURE__*/ (function (_super) { /***/ }), -/* 220 */ +/* 216 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bindCallback", function() { return bindCallback; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(205); -/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(172); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(200); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(201); +/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(217); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(168); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(196); /** PURE_IMPORTS_START _Observable,_AsyncSubject,_operators_map,_util_isArray,_util_isScheduler PURE_IMPORTS_END */ @@ -23311,15 +22949,15 @@ function dispatchError(state) { /***/ }), -/* 221 */ +/* 217 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "map", function() { return map; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MapOperator", function() { return MapOperator; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -23368,17 +23006,17 @@ var MapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 222 */ +/* 218 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bindNodeCallback", function() { return bindNodeCallback; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(205); -/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(200); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(172); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(201); +/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(217); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(196); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(168); /** PURE_IMPORTS_START _Observable,_AsyncSubject,_operators_map,_util_isScheduler,_util_isArray PURE_IMPORTS_END */ @@ -23489,7 +23127,7 @@ function dispatchError(arg) { /***/ }), -/* 223 */ +/* 219 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -23497,12 +23135,12 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return combineLatest; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CombineLatestOperator", function() { return CombineLatestOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CombineLatestSubscriber", function() { return CombineLatestSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(200); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(172); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(225); -/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(201); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(196); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(168); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221); +/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(197); /** PURE_IMPORTS_START tslib,_util_isScheduler,_util_isArray,_OuterSubscriber,_util_subscribeToResult,_fromArray PURE_IMPORTS_END */ @@ -23607,14 +23245,14 @@ var CombineLatestSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 224 */ +/* 220 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OuterSubscriber", function() { return OuterSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -23639,14 +23277,14 @@ var OuterSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 225 */ +/* 221 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeToResult", function() { return subscribeToResult; }); -/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(226); -/* harmony import */ var _subscribeTo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(227); +/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(222); +/* harmony import */ var _subscribeTo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(223); /** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo PURE_IMPORTS_END */ @@ -23658,14 +23296,14 @@ function subscribeToResult(outerSubscriber, result, outerValue, outerIndex) { /***/ }), -/* 226 */ +/* 222 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InnerSubscriber", function() { return InnerSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -23697,22 +23335,22 @@ var InnerSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 227 */ +/* 223 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeTo", function() { return subscribeTo; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _subscribeToArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(202); -/* harmony import */ var _subscribeToPromise__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(228); -/* harmony import */ var _subscribeToIterable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(229); -/* harmony import */ var _subscribeToObservable__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(231); -/* harmony import */ var _isArrayLike__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(232); -/* harmony import */ var _isPromise__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(233); -/* harmony import */ var _isObject__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(173); -/* harmony import */ var _symbol_iterator__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(230); -/* harmony import */ var _symbol_observable__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(178); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _subscribeToArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(198); +/* harmony import */ var _subscribeToPromise__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(224); +/* harmony import */ var _subscribeToIterable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(225); +/* harmony import */ var _subscribeToObservable__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(227); +/* harmony import */ var _isArrayLike__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(228); +/* harmony import */ var _isPromise__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(229); +/* harmony import */ var _isObject__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(169); +/* harmony import */ var _symbol_iterator__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(226); +/* harmony import */ var _symbol_observable__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(174); /** PURE_IMPORTS_START _Observable,_subscribeToArray,_subscribeToPromise,_subscribeToIterable,_subscribeToObservable,_isArrayLike,_isPromise,_isObject,_symbol_iterator,_symbol_observable PURE_IMPORTS_END */ @@ -23760,13 +23398,13 @@ var subscribeTo = function (result) { /***/ }), -/* 228 */ +/* 224 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeToPromise", function() { return subscribeToPromise; }); -/* harmony import */ var _hostReportError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(170); +/* harmony import */ var _hostReportError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); /** PURE_IMPORTS_START _hostReportError PURE_IMPORTS_END */ var subscribeToPromise = function (promise) { @@ -23785,13 +23423,13 @@ var subscribeToPromise = function (promise) { /***/ }), -/* 229 */ +/* 225 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeToIterable", function() { return subscribeToIterable; }); -/* harmony import */ var _symbol_iterator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(230); +/* harmony import */ var _symbol_iterator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(226); /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */ var subscribeToIterable = function (iterable) { @@ -23822,7 +23460,7 @@ var subscribeToIterable = function (iterable) { /***/ }), -/* 230 */ +/* 226 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -23843,13 +23481,13 @@ var $$iterator = iterator; /***/ }), -/* 231 */ +/* 227 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeToObservable", function() { return subscribeToObservable; }); -/* harmony import */ var _symbol_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(178); +/* harmony import */ var _symbol_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(174); /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */ var subscribeToObservable = function (obj) { @@ -23867,7 +23505,7 @@ var subscribeToObservable = function (obj) { /***/ }), -/* 232 */ +/* 228 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -23879,7 +23517,7 @@ var isArrayLike = (function (x) { return x && typeof x.length === 'number' && ty /***/ }), -/* 233 */ +/* 229 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -23893,16 +23531,16 @@ function isPromise(value) { /***/ }), -/* 234 */ +/* 230 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return concat; }); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(200); -/* harmony import */ var _of__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(199); -/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(235); -/* harmony import */ var _operators_concatAll__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(241); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(196); +/* harmony import */ var _of__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(195); +/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(231); +/* harmony import */ var _operators_concatAll__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(237); /** PURE_IMPORTS_START _util_isScheduler,_of,_from,_operators_concatAll PURE_IMPORTS_END */ @@ -23922,22 +23560,22 @@ function concat() { /***/ }), -/* 235 */ +/* 231 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "from", function() { return from; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _util_isPromise__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(233); -/* harmony import */ var _util_isArrayLike__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(232); -/* harmony import */ var _util_isInteropObservable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(236); -/* harmony import */ var _util_isIterable__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(237); -/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(201); -/* harmony import */ var _fromPromise__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(238); -/* harmony import */ var _fromIterable__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(239); -/* harmony import */ var _fromObservable__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(240); -/* harmony import */ var _util_subscribeTo__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(227); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _util_isPromise__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(229); +/* harmony import */ var _util_isArrayLike__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(228); +/* harmony import */ var _util_isInteropObservable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(232); +/* harmony import */ var _util_isIterable__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(233); +/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(197); +/* harmony import */ var _fromPromise__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(234); +/* harmony import */ var _fromIterable__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(235); +/* harmony import */ var _fromObservable__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(236); +/* harmony import */ var _util_subscribeTo__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(223); /** PURE_IMPORTS_START _Observable,_util_isPromise,_util_isArrayLike,_util_isInteropObservable,_util_isIterable,_fromArray,_fromPromise,_fromIterable,_fromObservable,_util_subscribeTo PURE_IMPORTS_END */ @@ -23976,13 +23614,13 @@ function from(input, scheduler) { /***/ }), -/* 236 */ +/* 232 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isInteropObservable", function() { return isInteropObservable; }); -/* harmony import */ var _symbol_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(178); +/* harmony import */ var _symbol_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(174); /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */ function isInteropObservable(input) { @@ -23992,13 +23630,13 @@ function isInteropObservable(input) { /***/ }), -/* 237 */ +/* 233 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isIterable", function() { return isIterable; }); -/* harmony import */ var _symbol_iterator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(230); +/* harmony import */ var _symbol_iterator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(226); /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */ function isIterable(input) { @@ -24008,15 +23646,15 @@ function isIterable(input) { /***/ }), -/* 238 */ +/* 234 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromPromise", function() { return fromPromise; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); -/* harmony import */ var _util_subscribeToPromise__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(228); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); +/* harmony import */ var _util_subscribeToPromise__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(224); /** PURE_IMPORTS_START _Observable,_Subscription,_util_subscribeToPromise PURE_IMPORTS_END */ @@ -24046,16 +23684,16 @@ function fromPromise(input, scheduler) { /***/ }), -/* 239 */ +/* 235 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromIterable", function() { return fromIterable; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); -/* harmony import */ var _symbol_iterator__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(230); -/* harmony import */ var _util_subscribeToIterable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(229); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); +/* harmony import */ var _symbol_iterator__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(226); +/* harmony import */ var _util_subscribeToIterable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(225); /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_iterator,_util_subscribeToIterable PURE_IMPORTS_END */ @@ -24111,16 +23749,16 @@ function fromIterable(input, scheduler) { /***/ }), -/* 240 */ +/* 236 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromObservable", function() { return fromObservable; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); -/* harmony import */ var _symbol_observable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(178); -/* harmony import */ var _util_subscribeToObservable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(231); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); +/* harmony import */ var _symbol_observable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(174); +/* harmony import */ var _util_subscribeToObservable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(227); /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_observable,_util_subscribeToObservable PURE_IMPORTS_END */ @@ -24149,13 +23787,13 @@ function fromObservable(input, scheduler) { /***/ }), -/* 241 */ +/* 237 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatAll", function() { return concatAll; }); -/* harmony import */ var _mergeAll__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(242); +/* harmony import */ var _mergeAll__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(238); /** PURE_IMPORTS_START _mergeAll PURE_IMPORTS_END */ function concatAll() { @@ -24165,14 +23803,14 @@ function concatAll() { /***/ }), -/* 242 */ +/* 238 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeAll", function() { return mergeAll; }); -/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(243); -/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(215); +/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(239); +/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(211); /** PURE_IMPORTS_START _mergeMap,_util_identity PURE_IMPORTS_END */ @@ -24186,7 +23824,7 @@ function mergeAll(concurrent) { /***/ }), -/* 243 */ +/* 239 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -24194,11 +23832,11 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeMap", function() { return mergeMap; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MergeMapOperator", function() { return MergeMapOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MergeMapSubscriber", function() { return MergeMapSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(225); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(224); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(235); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(221); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(220); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(217); +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(231); /** PURE_IMPORTS_START tslib,_util_subscribeToResult,_OuterSubscriber,_map,_observable_from PURE_IMPORTS_END */ @@ -24297,15 +23935,15 @@ var MergeMapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 244 */ +/* 240 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defer", function() { return defer; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(235); -/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(198); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(231); +/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(194); /** PURE_IMPORTS_START _Observable,_from,_empty PURE_IMPORTS_END */ @@ -24328,19 +23966,19 @@ function defer(observableFactory) { /***/ }), -/* 245 */ +/* 241 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forkJoin", function() { return forkJoin; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(163); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(172); -/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(198); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(225); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(224); -/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(221); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(159); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(168); +/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(194); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(220); +/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(217); /** PURE_IMPORTS_START tslib,_Observable,_util_isArray,_empty,_util_subscribeToResult,_OuterSubscriber,_operators_map PURE_IMPORTS_END */ @@ -24418,16 +24056,16 @@ var ForkJoinSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 246 */ +/* 242 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromEvent", function() { return fromEvent; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(172); -/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(167); -/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(168); +/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(163); +/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(217); /** PURE_IMPORTS_START _Observable,_util_isArray,_util_isFunction,_operators_map PURE_IMPORTS_END */ @@ -24494,16 +24132,16 @@ function isEventTarget(sourceObj) { /***/ }), -/* 247 */ +/* 243 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromEventPattern", function() { return fromEventPattern; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(172); -/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(167); -/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(168); +/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(163); +/* harmony import */ var _operators_map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(217); /** PURE_IMPORTS_START _Observable,_util_isArray,_util_isFunction,_operators_map PURE_IMPORTS_END */ @@ -24539,15 +24177,15 @@ function fromEventPattern(addHandler, removeHandler, resultSelector) { /***/ }), -/* 248 */ +/* 244 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "generate", function() { return generate; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(215); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(200); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(211); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(196); /** PURE_IMPORTS_START _Observable,_util_identity,_util_isScheduler PURE_IMPORTS_END */ @@ -24676,14 +24314,14 @@ function dispatch(state) { /***/ }), -/* 249 */ +/* 245 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "iif", function() { return iif; }); -/* harmony import */ var _defer__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(244); -/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(198); +/* harmony import */ var _defer__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(240); +/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(194); /** PURE_IMPORTS_START _defer,_empty PURE_IMPORTS_END */ @@ -24700,15 +24338,15 @@ function iif(condition, trueResult, falseResult) { /***/ }), -/* 250 */ +/* 246 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "interval", function() { return interval; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(210); -/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(251); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(206); +/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(247); /** PURE_IMPORTS_START _Observable,_scheduler_async,_util_isNumeric PURE_IMPORTS_END */ @@ -24740,13 +24378,13 @@ function dispatch(state) { /***/ }), -/* 251 */ +/* 247 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isNumeric", function() { return isNumeric; }); -/* harmony import */ var _isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(172); +/* harmony import */ var _isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(168); /** PURE_IMPORTS_START _isArray PURE_IMPORTS_END */ function isNumeric(val) { @@ -24756,16 +24394,16 @@ function isNumeric(val) { /***/ }), -/* 252 */ +/* 248 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return merge; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(200); -/* harmony import */ var _operators_mergeAll__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(242); -/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(201); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(196); +/* harmony import */ var _operators_mergeAll__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(238); +/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(197); /** PURE_IMPORTS_START _Observable,_util_isScheduler,_operators_mergeAll,_fromArray PURE_IMPORTS_END */ @@ -24797,15 +24435,15 @@ function merge() { /***/ }), -/* 253 */ +/* 249 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NEVER", function() { return NEVER; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "never", function() { return never; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _util_noop__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(180); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _util_noop__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(176); /** PURE_IMPORTS_START _Observable,_util_noop PURE_IMPORTS_END */ @@ -24817,16 +24455,16 @@ function never() { /***/ }), -/* 254 */ +/* 250 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return onErrorResumeNext; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(235); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(172); -/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(198); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(231); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(168); +/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(194); /** PURE_IMPORTS_START _Observable,_from,_util_isArray,_empty PURE_IMPORTS_END */ @@ -24857,15 +24495,15 @@ function onErrorResumeNext() { /***/ }), -/* 255 */ +/* 251 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pairs", function() { return pairs; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dispatch", function() { return dispatch; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */ @@ -24908,7 +24546,7 @@ function dispatch(state) { /***/ }), -/* 256 */ +/* 252 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -24916,11 +24554,11 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "race", function() { return race; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RaceOperator", function() { return RaceOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RaceSubscriber", function() { return RaceSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(172); -/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(201); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(168); +/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(197); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_util_isArray,_fromArray,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -25002,14 +24640,14 @@ var RaceSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 257 */ +/* 253 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "range", function() { return range; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dispatch", function() { return dispatch; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */ function range(start, count, scheduler) { @@ -25060,16 +24698,16 @@ function dispatch(state) { /***/ }), -/* 258 */ +/* 254 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timer", function() { return timer; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(210); -/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(251); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(200); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(206); +/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(247); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(196); /** PURE_IMPORTS_START _Observable,_scheduler_async,_util_isNumeric,_util_isScheduler PURE_IMPORTS_END */ @@ -25114,15 +24752,15 @@ function dispatch(state) { /***/ }), -/* 259 */ +/* 255 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "using", function() { return using; }); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(163); -/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(235); -/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(198); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(159); +/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(231); +/* harmony import */ var _empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(194); /** PURE_IMPORTS_START _Observable,_from,_empty PURE_IMPORTS_END */ @@ -25159,7 +24797,7 @@ function using(resourceFactory, observableFactory) { /***/ }), -/* 260 */ +/* 256 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -25167,13 +24805,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return zip; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZipOperator", function() { return ZipOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZipSubscriber", function() { return ZipSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(201); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(172); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(165); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(225); -/* harmony import */ var _internal_symbol_iterator__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(230); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _fromArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(197); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(168); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(161); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(221); +/* harmony import */ var _internal_symbol_iterator__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(226); /** PURE_IMPORTS_START tslib,_fromArray,_util_isArray,_Subscriber,_OuterSubscriber,_util_subscribeToResult,_.._internal_symbol_iterator PURE_IMPORTS_END */ @@ -25393,320 +25031,320 @@ var ZipBufferIterator = /*@__PURE__*/ (function (_super) { /***/ }), -/* 261 */ +/* 257 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(262); +/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(258); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__["audit"]; }); -/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(263); +/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(259); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__["auditTime"]; }); -/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(264); +/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(260); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__["buffer"]; }); -/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(265); +/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(261); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__["bufferCount"]; }); -/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(266); +/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(262); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__["bufferTime"]; }); -/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(267); +/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(263); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__["bufferToggle"]; }); -/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(268); +/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(264); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__["bufferWhen"]; }); -/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(269); +/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(265); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__["catchError"]; }); -/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(270); +/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(266); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__["combineAll"]; }); -/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(271); +/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(267); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__["combineLatest"]; }); -/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(272); +/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(268); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__["concat"]; }); -/* harmony import */ var _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(241); +/* harmony import */ var _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(237); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatAll", function() { return _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__["concatAll"]; }); -/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(273); +/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(269); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__["concatMap"]; }); -/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(274); +/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(270); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__["concatMapTo"]; }); -/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(275); +/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(271); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "count", function() { return _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__["count"]; }); -/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(276); +/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(272); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__["debounce"]; }); -/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(277); +/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(273); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__["debounceTime"]; }); -/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(278); +/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(274); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__["defaultIfEmpty"]; }); -/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(279); +/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(275); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__["delay"]; }); -/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(281); +/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(277); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__["delayWhen"]; }); -/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(282); +/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(278); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__["dematerialize"]; }); -/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(283); +/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(279); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__["distinct"]; }); -/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(284); +/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(280); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__["distinctUntilChanged"]; }); -/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(285); +/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(281); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__["distinctUntilKeyChanged"]; }); -/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(286); +/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(282); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__["elementAt"]; }); -/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(291); +/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(287); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__["endWith"]; }); -/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(292); +/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(288); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "every", function() { return _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__["every"]; }); -/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(293); +/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(289); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__["exhaust"]; }); -/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(294); +/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(290); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__["exhaustMap"]; }); -/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(295); +/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(291); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__["expand"]; }); -/* harmony import */ var _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(287); +/* harmony import */ var _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(283); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "filter", function() { return _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__["filter"]; }); -/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(296); +/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(292); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__["finalize"]; }); -/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(297); +/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(293); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "find", function() { return _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__["find"]; }); -/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(298); +/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(294); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__["findIndex"]; }); -/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(299); +/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(295); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "first", function() { return _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__["first"]; }); -/* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(186); +/* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(182); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "groupBy", function() { return _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__["groupBy"]; }); -/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(300); +/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(296); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__["ignoreElements"]; }); -/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(301); +/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(297); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__["isEmpty"]; }); -/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(302); +/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(298); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "last", function() { return _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__["last"]; }); -/* harmony import */ var _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(221); +/* harmony import */ var _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(217); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "map", function() { return _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__["map"]; }); -/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(304); +/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(300); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__["mapTo"]; }); -/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(305); +/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(301); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__["materialize"]; }); -/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(306); +/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(302); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "max", function() { return _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__["max"]; }); -/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(309); +/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(305); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__["merge"]; }); -/* harmony import */ var _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(242); +/* harmony import */ var _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(238); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeAll", function() { return _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__["mergeAll"]; }); -/* harmony import */ var _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(243); +/* harmony import */ var _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(239); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["mergeMap"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "flatMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["mergeMap"]; }); -/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(310); +/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(306); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__["mergeMapTo"]; }); -/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(311); +/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(307); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__["mergeScan"]; }); -/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(312); +/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(308); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "min", function() { return _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__["min"]; }); -/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(313); +/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(309); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__["multicast"]; }); -/* harmony import */ var _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(196); +/* harmony import */ var _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(192); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "observeOn", function() { return _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__["observeOn"]; }); -/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(314); +/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(310); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__["onErrorResumeNext"]; }); -/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(315); +/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(311); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__["pairwise"]; }); -/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(316); +/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(312); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__["partition"]; }); -/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(318); +/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(314); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__["pluck"]; }); -/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(319); +/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(315); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__["publish"]; }); -/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(320); +/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(316); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__["publishBehavior"]; }); -/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(321); +/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(317); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__["publishLast"]; }); -/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(322); +/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(318); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__["publishReplay"]; }); -/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(323); +/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(319); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "race", function() { return _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__["race"]; }); -/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(307); +/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(303); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__["reduce"]; }); -/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(324); +/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(320); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__["repeat"]; }); -/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(325); +/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(321); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__["repeatWhen"]; }); -/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(326); +/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(322); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__["retry"]; }); -/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(327); +/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(323); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__["retryWhen"]; }); -/* harmony import */ var _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(185); +/* harmony import */ var _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(181); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "refCount", function() { return _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__["refCount"]; }); -/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(328); +/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(324); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__["sample"]; }); -/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(329); +/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(325); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__["sampleTime"]; }); -/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(308); +/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(304); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__["scan"]; }); -/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(330); +/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(326); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__["sequenceEqual"]; }); -/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(331); +/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(327); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "share", function() { return _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__["share"]; }); -/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(332); +/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(328); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__["shareReplay"]; }); -/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(333); +/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(329); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "single", function() { return _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__["single"]; }); -/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(334); +/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(330); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__["skip"]; }); -/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(335); +/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(331); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__["skipLast"]; }); -/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(336); +/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(332); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__["skipUntil"]; }); -/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(337); +/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(333); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__["skipWhile"]; }); -/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(338); +/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(334); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__["startWith"]; }); -/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(339); +/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(335); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__["subscribeOn"]; }); -/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(341); +/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(337); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__["switchAll"]; }); -/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(342); +/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(338); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__["switchMap"]; }); -/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(343); +/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(339); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__["switchMapTo"]; }); -/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(290); +/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(286); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "take", function() { return _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__["take"]; }); -/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(303); +/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(299); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__["takeLast"]; }); -/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(344); +/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(340); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__["takeUntil"]; }); -/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(345); +/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(341); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__["takeWhile"]; }); -/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(289); +/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(285); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__["tap"]; }); -/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(346); +/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(342); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__["throttle"]; }); -/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(347); +/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(343); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__["throttleTime"]; }); -/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(288); +/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(284); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__["throwIfEmpty"]; }); -/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(348); +/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(344); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__["timeInterval"]; }); -/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(349); +/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(345); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__["timeout"]; }); -/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(350); +/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(346); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__["timeoutWith"]; }); -/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(351); +/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(347); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__["timestamp"]; }); -/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(352); +/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(348); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__["toArray"]; }); -/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(353); +/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(349); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "window", function() { return _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__["window"]; }); -/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(354); +/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(350); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__["windowCount"]; }); -/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(355); +/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(351); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__["windowTime"]; }); -/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(356); +/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(352); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__["windowToggle"]; }); -/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(357); +/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(353); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__["windowWhen"]; }); -/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(358); +/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(354); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__["withLatestFrom"]; }); -/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(359); +/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(355); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__["zip"]; }); -/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(360); +/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(356); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__["zipAll"]; }); /** PURE_IMPORTS_START PURE_IMPORTS_END */ @@ -25818,17 +25456,17 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 262 */ +/* 258 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return audit; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(175); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(171); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_util_tryCatch,_util_errorObject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -25901,15 +25539,15 @@ var AuditSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 263 */ +/* 259 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return auditTime; }); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(210); -/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(262); -/* harmony import */ var _observable_timer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(258); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(206); +/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(258); +/* harmony import */ var _observable_timer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(254); /** PURE_IMPORTS_START _scheduler_async,_audit,_observable_timer PURE_IMPORTS_END */ @@ -25924,15 +25562,15 @@ function auditTime(duration, scheduler) { /***/ }), -/* 264 */ +/* 260 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return buffer; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -25973,14 +25611,14 @@ var BufferSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 265 */ +/* 261 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return bufferCount; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -26074,16 +25712,16 @@ var BufferSkipCountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 266 */ +/* 262 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return bufferTime; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(210); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(165); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(200); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(206); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(161); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(196); /** PURE_IMPORTS_START tslib,_scheduler_async,_Subscriber,_util_isScheduler PURE_IMPORTS_END */ @@ -26235,16 +25873,16 @@ function dispatchBufferClose(arg) { /***/ }), -/* 267 */ +/* 263 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return bufferToggle; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(224); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220); /** PURE_IMPORTS_START tslib,_Subscription,_util_subscribeToResult,_OuterSubscriber PURE_IMPORTS_END */ @@ -26355,18 +25993,18 @@ var BufferToggleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 268 */ +/* 264 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return bufferWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(171); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(175); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(167); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_Subscription,_util_tryCatch,_util_errorObject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -26452,15 +26090,15 @@ var BufferWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 269 */ +/* 265 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return catchError; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -26509,13 +26147,13 @@ var CatchSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 270 */ +/* 266 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return combineAll; }); -/* harmony import */ var _observable_combineLatest__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(223); +/* harmony import */ var _observable_combineLatest__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(219); /** PURE_IMPORTS_START _observable_combineLatest PURE_IMPORTS_END */ function combineAll(project) { @@ -26525,15 +26163,15 @@ function combineAll(project) { /***/ }), -/* 271 */ +/* 267 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return combineLatest; }); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(172); -/* harmony import */ var _observable_combineLatest__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(223); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(235); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(168); +/* harmony import */ var _observable_combineLatest__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(219); +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(231); /** PURE_IMPORTS_START _util_isArray,_observable_combineLatest,_observable_from PURE_IMPORTS_END */ @@ -26557,13 +26195,13 @@ function combineLatest() { /***/ }), -/* 272 */ +/* 268 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return concat; }); -/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(234); +/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(230); /** PURE_IMPORTS_START _observable_concat PURE_IMPORTS_END */ function concat() { @@ -26577,13 +26215,13 @@ function concat() { /***/ }), -/* 273 */ +/* 269 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return concatMap; }); -/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(243); +/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(239); /** PURE_IMPORTS_START _mergeMap PURE_IMPORTS_END */ function concatMap(project, resultSelector) { @@ -26593,13 +26231,13 @@ function concatMap(project, resultSelector) { /***/ }), -/* 274 */ +/* 270 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return concatMapTo; }); -/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(273); +/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(269); /** PURE_IMPORTS_START _concatMap PURE_IMPORTS_END */ function concatMapTo(innerObservable, resultSelector) { @@ -26609,14 +26247,14 @@ function concatMapTo(innerObservable, resultSelector) { /***/ }), -/* 275 */ +/* 271 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "count", function() { return count; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -26674,15 +26312,15 @@ var CountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 276 */ +/* 272 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return debounce; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -26762,15 +26400,15 @@ var DebounceSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 277 */ +/* 273 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return debounceTime; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(210); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(206); /** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async PURE_IMPORTS_END */ @@ -26838,14 +26476,14 @@ function dispatchNext(subscriber) { /***/ }), -/* 278 */ +/* 274 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return defaultIfEmpty; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -26888,17 +26526,17 @@ var DefaultIfEmptySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 279 */ +/* 275 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return delay; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(210); -/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(280); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(165); -/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(197); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(206); +/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(276); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(161); +/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(193); /** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_Subscriber,_Notification PURE_IMPORTS_END */ @@ -26992,7 +26630,7 @@ var DelayMessage = /*@__PURE__*/ (function () { /***/ }), -/* 280 */ +/* 276 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -27006,17 +26644,17 @@ function isDate(value) { /***/ }), -/* 281 */ +/* 277 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return delayWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(163); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(159); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_Subscriber,_Observable,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -27147,14 +26785,14 @@ var SubscriptionDelaySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 282 */ +/* 278 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return dematerialize; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -27185,16 +26823,16 @@ var DeMaterializeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 283 */ +/* 279 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return distinct; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DistinctSubscriber", function() { return DistinctSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -27263,16 +26901,16 @@ var DistinctSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 284 */ +/* 280 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return distinctUntilChanged; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(175); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); /** PURE_IMPORTS_START tslib,_Subscriber,_util_tryCatch,_util_errorObject PURE_IMPORTS_END */ @@ -27335,13 +26973,13 @@ var DistinctUntilChangedSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 285 */ +/* 281 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return distinctUntilKeyChanged; }); -/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(284); +/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(280); /** PURE_IMPORTS_START _distinctUntilChanged PURE_IMPORTS_END */ function distinctUntilKeyChanged(key, compare) { @@ -27351,17 +26989,17 @@ function distinctUntilKeyChanged(key, compare) { /***/ }), -/* 286 */ +/* 282 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return elementAt; }); -/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(217); -/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(287); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(288); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(278); -/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(290); +/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(213); +/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(283); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(284); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(274); +/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(286); /** PURE_IMPORTS_START _util_ArgumentOutOfRangeError,_filter,_throwIfEmpty,_defaultIfEmpty,_take PURE_IMPORTS_END */ @@ -27383,14 +27021,14 @@ function elementAt(index, defaultValue) { /***/ }), -/* 287 */ +/* 283 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filter", function() { return filter; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -27437,14 +27075,14 @@ var FilterSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 288 */ +/* 284 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return throwIfEmpty; }); -/* harmony import */ var _tap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(289); -/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(218); +/* harmony import */ var _tap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(285); +/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(214); /** PURE_IMPORTS_START _tap,_util_EmptyError PURE_IMPORTS_END */ @@ -27469,16 +27107,16 @@ function defaultErrorFactory() { /***/ }), -/* 289 */ +/* 285 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return tap; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _util_noop__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(180); -/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(167); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _util_noop__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(176); +/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(163); /** PURE_IMPORTS_START tslib,_Subscriber,_util_noop,_util_isFunction PURE_IMPORTS_END */ @@ -27557,16 +27195,16 @@ var TapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 290 */ +/* 286 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "take", function() { return take; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(217); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(198); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(213); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(194); /** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */ @@ -27619,17 +27257,17 @@ var TakeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 291 */ +/* 287 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return endWith; }); -/* harmony import */ var _observable_fromArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(201); -/* harmony import */ var _observable_scalar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(203); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(198); -/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(234); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(200); +/* harmony import */ var _observable_fromArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(197); +/* harmony import */ var _observable_scalar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(199); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(194); +/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(230); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(196); /** PURE_IMPORTS_START _observable_fromArray,_observable_scalar,_observable_empty,_observable_concat,_util_isScheduler PURE_IMPORTS_END */ @@ -27665,14 +27303,14 @@ function endWith() { /***/ }), -/* 292 */ +/* 288 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "every", function() { return every; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -27727,15 +27365,15 @@ var EverySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 293 */ +/* 289 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return exhaust; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -27784,17 +27422,17 @@ var SwitchFirstSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 294 */ +/* 290 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return exhaustMap; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(235); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(217); +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(231); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult,_map,_observable_from PURE_IMPORTS_END */ @@ -27870,7 +27508,7 @@ var ExhaustMapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 295 */ +/* 291 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -27878,11 +27516,11 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return expand; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExpandOperator", function() { return ExpandOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExpandSubscriber", function() { return ExpandSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(175); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(171); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_util_tryCatch,_util_errorObject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -27986,15 +27624,15 @@ var ExpandSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 296 */ +/* 292 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return finalize; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(171); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(167); /** PURE_IMPORTS_START tslib,_Subscriber,_Subscription PURE_IMPORTS_END */ @@ -28024,7 +27662,7 @@ var FinallySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 297 */ +/* 293 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -28032,8 +27670,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "find", function() { return find; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FindValueOperator", function() { return FindValueOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FindValueSubscriber", function() { return FindValueSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -28095,13 +27733,13 @@ var FindValueSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 298 */ +/* 294 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return findIndex; }); -/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(297); +/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(293); /** PURE_IMPORTS_START _operators_find PURE_IMPORTS_END */ function findIndex(predicate, thisArg) { @@ -28111,18 +27749,18 @@ function findIndex(predicate, thisArg) { /***/ }), -/* 299 */ +/* 295 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "first", function() { return first; }); -/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(218); -/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(287); -/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(290); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(278); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(288); -/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(215); +/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(214); +/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(283); +/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(286); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(274); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(284); +/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(211); /** PURE_IMPORTS_START _util_EmptyError,_filter,_take,_defaultIfEmpty,_throwIfEmpty,_util_identity PURE_IMPORTS_END */ @@ -28138,14 +27776,14 @@ function first(predicate, defaultValue) { /***/ }), -/* 300 */ +/* 296 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return ignoreElements; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -28175,14 +27813,14 @@ var IgnoreElementsSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 301 */ +/* 297 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return isEmpty; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -28219,18 +27857,18 @@ var IsEmptySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 302 */ +/* 298 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "last", function() { return last; }); -/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(218); -/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(287); -/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(303); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(288); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(278); -/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(215); +/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(214); +/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(283); +/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(299); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(284); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(274); +/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(211); /** PURE_IMPORTS_START _util_EmptyError,_filter,_takeLast,_throwIfEmpty,_defaultIfEmpty,_util_identity PURE_IMPORTS_END */ @@ -28246,16 +27884,16 @@ function last(predicate, defaultValue) { /***/ }), -/* 303 */ +/* 299 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return takeLast; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(217); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(198); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(213); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(194); /** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */ @@ -28323,14 +27961,14 @@ var TakeLastSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 304 */ +/* 300 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return mapTo; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -28362,15 +28000,15 @@ var MapToSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 305 */ +/* 301 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return materialize; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(197); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(193); /** PURE_IMPORTS_START tslib,_Subscriber,_Notification PURE_IMPORTS_END */ @@ -28412,13 +28050,13 @@ var MaterializeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 306 */ +/* 302 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(307); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(303); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function max(comparer) { @@ -28431,16 +28069,16 @@ function max(comparer) { /***/ }), -/* 307 */ +/* 303 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return reduce; }); -/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(308); -/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(303); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(278); -/* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(179); +/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(304); +/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(299); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(274); +/* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(175); /** PURE_IMPORTS_START _scan,_takeLast,_defaultIfEmpty,_util_pipe PURE_IMPORTS_END */ @@ -28462,14 +28100,14 @@ function reduce(accumulator, seed) { /***/ }), -/* 308 */ +/* 304 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return scan; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -28544,13 +28182,13 @@ var ScanSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 309 */ +/* 305 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return merge; }); -/* harmony import */ var _observable_merge__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(252); +/* harmony import */ var _observable_merge__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(248); /** PURE_IMPORTS_START _observable_merge PURE_IMPORTS_END */ function merge() { @@ -28564,13 +28202,13 @@ function merge() { /***/ }), -/* 310 */ +/* 306 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return mergeMapTo; }); -/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(243); +/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(239); /** PURE_IMPORTS_START _mergeMap PURE_IMPORTS_END */ function mergeMapTo(innerObservable, resultSelector, concurrent) { @@ -28589,7 +28227,7 @@ function mergeMapTo(innerObservable, resultSelector, concurrent) { /***/ }), -/* 311 */ +/* 307 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -28597,11 +28235,11 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return mergeScan; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MergeScanOperator", function() { return MergeScanOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MergeScanSubscriber", function() { return MergeScanSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(175); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(225); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(224); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(171); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(220); /** PURE_IMPORTS_START tslib,_util_tryCatch,_util_errorObject,_util_subscribeToResult,_OuterSubscriber PURE_IMPORTS_END */ @@ -28696,13 +28334,13 @@ var MergeScanSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 312 */ +/* 308 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(307); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(303); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function min(comparer) { @@ -28715,14 +28353,14 @@ function min(comparer) { /***/ }), -/* 313 */ +/* 309 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return multicast; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MulticastOperator", function() { return MulticastOperator; }); -/* harmony import */ var _observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(181); +/* harmony import */ var _observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(177); /** PURE_IMPORTS_START _observable_ConnectableObservable PURE_IMPORTS_END */ function multicast(subjectOrSubjectFactory, selector) { @@ -28764,18 +28402,18 @@ var MulticastOperator = /*@__PURE__*/ (function () { /***/ }), -/* 314 */ +/* 310 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return onErrorResumeNext; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNextStatic", function() { return onErrorResumeNextStatic; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(235); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(172); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(231); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(168); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_observable_from,_util_isArray,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -28848,14 +28486,14 @@ var OnErrorResumeNextSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 315 */ +/* 311 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return pairwise; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -28892,14 +28530,14 @@ var PairwiseSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 316 */ +/* 312 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return partition; }); -/* harmony import */ var _util_not__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(317); -/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(287); +/* harmony import */ var _util_not__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(313); +/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(283); /** PURE_IMPORTS_START _util_not,_filter PURE_IMPORTS_END */ @@ -28915,7 +28553,7 @@ function partition(predicate, thisArg) { /***/ }), -/* 317 */ +/* 313 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -28934,13 +28572,13 @@ function not(pred, thisArg) { /***/ }), -/* 318 */ +/* 314 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return pluck; }); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(221); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(217); /** PURE_IMPORTS_START _map PURE_IMPORTS_END */ function pluck() { @@ -28974,14 +28612,14 @@ function plucker(props, length) { /***/ }), -/* 319 */ +/* 315 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return publish; }); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(182); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(313); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(178); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(309); /** PURE_IMPORTS_START _Subject,_multicast PURE_IMPORTS_END */ @@ -28994,14 +28632,14 @@ function publish(selector) { /***/ }), -/* 320 */ +/* 316 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return publishBehavior; }); -/* harmony import */ var _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(187); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(313); +/* harmony import */ var _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(183); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(309); /** PURE_IMPORTS_START _BehaviorSubject,_multicast PURE_IMPORTS_END */ @@ -29012,14 +28650,14 @@ function publishBehavior(value) { /***/ }), -/* 321 */ +/* 317 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return publishLast; }); -/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(205); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(313); +/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(201); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(309); /** PURE_IMPORTS_START _AsyncSubject,_multicast PURE_IMPORTS_END */ @@ -29030,14 +28668,14 @@ function publishLast() { /***/ }), -/* 322 */ +/* 318 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return publishReplay; }); -/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(188); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(313); +/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(184); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(309); /** PURE_IMPORTS_START _ReplaySubject,_multicast PURE_IMPORTS_END */ @@ -29053,14 +28691,14 @@ function publishReplay(bufferSize, windowTime, selectorOrScheduler, scheduler) { /***/ }), -/* 323 */ +/* 319 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "race", function() { return race; }); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(172); -/* harmony import */ var _observable_race__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(256); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(168); +/* harmony import */ var _observable_race__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(252); /** PURE_IMPORTS_START _util_isArray,_observable_race PURE_IMPORTS_END */ @@ -29080,15 +28718,15 @@ function race() { /***/ }), -/* 324 */ +/* 320 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return repeat; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(198); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(194); /** PURE_IMPORTS_START tslib,_Subscriber,_observable_empty PURE_IMPORTS_END */ @@ -29145,18 +28783,18 @@ var RepeatSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 325 */ +/* 321 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return repeatWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(175); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_Subject,_util_tryCatch,_util_errorObject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -29241,14 +28879,14 @@ var RepeatWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 326 */ +/* 322 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return retry; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -29294,18 +28932,18 @@ var RetrySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 327 */ +/* 323 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return retryWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(175); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_Subject,_util_tryCatch,_util_errorObject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -29383,15 +29021,15 @@ var RetryWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 328 */ +/* 324 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return sample; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -29440,15 +29078,15 @@ var SampleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 329 */ +/* 325 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return sampleTime; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(210); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(206); /** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async PURE_IMPORTS_END */ @@ -29500,7 +29138,7 @@ function dispatchNotification(state) { /***/ }), -/* 330 */ +/* 326 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -29508,10 +29146,10 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return sequenceEqual; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SequenceEqualOperator", function() { return SequenceEqualOperator; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SequenceEqualSubscriber", function() { return SequenceEqualSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(175); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); /** PURE_IMPORTS_START tslib,_Subscriber,_util_tryCatch,_util_errorObject PURE_IMPORTS_END */ @@ -29619,15 +29257,15 @@ var SequenceEqualCompareToSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 331 */ +/* 327 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "share", function() { return share; }); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(313); -/* harmony import */ var _refCount__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(185); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(182); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(309); +/* harmony import */ var _refCount__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(181); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(178); /** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */ @@ -29642,13 +29280,13 @@ function share() { /***/ }), -/* 332 */ +/* 328 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return shareReplay; }); -/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(188); +/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(184); /** PURE_IMPORTS_START _ReplaySubject PURE_IMPORTS_END */ function shareReplay(bufferSize, windowTime, scheduler) { @@ -29691,15 +29329,15 @@ function shareReplayOperator(bufferSize, windowTime, scheduler) { /***/ }), -/* 333 */ +/* 329 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "single", function() { return single; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(218); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(214); /** PURE_IMPORTS_START tslib,_Subscriber,_util_EmptyError PURE_IMPORTS_END */ @@ -29771,14 +29409,14 @@ var SingleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 334 */ +/* 330 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return skip; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -29813,15 +29451,15 @@ var SkipSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 335 */ +/* 331 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return skipLast; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(217); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(213); /** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError PURE_IMPORTS_END */ @@ -29875,15 +29513,15 @@ var SkipLastSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 336 */ +/* 332 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return skipUntil; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -29927,14 +29565,14 @@ var SkipUntilSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 337 */ +/* 333 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return skipWhile; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -29983,17 +29621,17 @@ var SkipWhileSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 338 */ +/* 334 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return startWith; }); -/* harmony import */ var _observable_fromArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(201); -/* harmony import */ var _observable_scalar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(203); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(198); -/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(234); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(200); +/* harmony import */ var _observable_fromArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(197); +/* harmony import */ var _observable_scalar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(199); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(194); +/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(230); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(196); /** PURE_IMPORTS_START _observable_fromArray,_observable_scalar,_observable_empty,_observable_concat,_util_isScheduler PURE_IMPORTS_END */ @@ -30029,13 +29667,13 @@ function startWith() { /***/ }), -/* 339 */ +/* 335 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return subscribeOn; }); -/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(340); +/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(336); /** PURE_IMPORTS_START _observable_SubscribeOnObservable PURE_IMPORTS_END */ function subscribeOn(scheduler, delay) { @@ -30060,16 +29698,16 @@ var SubscribeOnOperator = /*@__PURE__*/ (function () { /***/ }), -/* 340 */ +/* 336 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubscribeOnObservable", function() { return SubscribeOnObservable; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(163); -/* harmony import */ var _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(206); -/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(251); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(159); +/* harmony import */ var _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(202); +/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(247); /** PURE_IMPORTS_START tslib,_Observable,_scheduler_asap,_util_isNumeric PURE_IMPORTS_END */ @@ -30124,14 +29762,14 @@ var SubscribeOnObservable = /*@__PURE__*/ (function (_super) { /***/ }), -/* 341 */ +/* 337 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return switchAll; }); -/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(342); -/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(215); +/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(338); +/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(211); /** PURE_IMPORTS_START _switchMap,_util_identity PURE_IMPORTS_END */ @@ -30142,17 +29780,17 @@ function switchAll() { /***/ }), -/* 342 */ +/* 338 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return switchMap; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(235); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(217); +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(231); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult,_map,_observable_from PURE_IMPORTS_END */ @@ -30226,13 +29864,13 @@ var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 343 */ +/* 339 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return switchMapTo; }); -/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(342); +/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(338); /** PURE_IMPORTS_START _switchMap PURE_IMPORTS_END */ function switchMapTo(innerObservable, resultSelector) { @@ -30242,15 +29880,15 @@ function switchMapTo(innerObservable, resultSelector) { /***/ }), -/* 344 */ +/* 340 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return takeUntil; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -30289,14 +29927,14 @@ var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 345 */ +/* 341 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return takeWhile; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ @@ -30347,16 +29985,16 @@ var TakeWhileSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 346 */ +/* 342 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaultThrottleConfig", function() { return defaultThrottleConfig; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return throttle; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -30451,16 +30089,16 @@ var ThrottleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 347 */ +/* 343 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return throttleTime; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(210); -/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(346); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(206); +/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(342); /** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async,_throttle PURE_IMPORTS_END */ @@ -30545,17 +30183,17 @@ function dispatchNext(arg) { /***/ }), -/* 348 */ +/* 344 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return timeInterval; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TimeInterval", function() { return TimeInterval; }); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(210); -/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(308); -/* harmony import */ var _observable_defer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(244); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(206); +/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(304); +/* harmony import */ var _observable_defer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(240); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(217); /** PURE_IMPORTS_START _scheduler_async,_scan,_observable_defer,_map PURE_IMPORTS_END */ @@ -30589,16 +30227,16 @@ var TimeInterval = /*@__PURE__*/ (function () { /***/ }), -/* 349 */ +/* 345 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return timeout; }); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(210); -/* harmony import */ var _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(219); -/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(350); -/* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(204); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(206); +/* harmony import */ var _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(215); +/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(346); +/* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(200); /** PURE_IMPORTS_START _scheduler_async,_util_TimeoutError,_timeoutWith,_observable_throwError PURE_IMPORTS_END */ @@ -30614,17 +30252,17 @@ function timeout(due, scheduler) { /***/ }), -/* 350 */ +/* 346 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return timeoutWith; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(210); -/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(280); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(206); +/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(276); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -30696,15 +30334,15 @@ var TimeoutWithSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 351 */ +/* 347 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return timestamp; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Timestamp", function() { return Timestamp; }); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(210); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(221); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(206); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(217); /** PURE_IMPORTS_START _scheduler_async,_map PURE_IMPORTS_END */ @@ -30726,13 +30364,13 @@ var Timestamp = /*@__PURE__*/ (function () { /***/ }), -/* 352 */ +/* 348 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return toArray; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(307); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(303); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function toArrayReducer(arr, item, index) { @@ -30749,16 +30387,16 @@ function toArray() { /***/ }), -/* 353 */ +/* 349 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "window", function() { return window; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -30829,15 +30467,15 @@ var WindowSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 354 */ +/* 350 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return windowCount; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(165); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(182); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(161); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(178); /** PURE_IMPORTS_START tslib,_Subscriber,_Subject PURE_IMPORTS_END */ @@ -30919,18 +30557,18 @@ var WindowCountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 355 */ +/* 351 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return windowTime; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(210); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(165); -/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(251); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(200); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(206); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(161); +/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(247); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(196); /** PURE_IMPORTS_START tslib,_Subject,_scheduler_async,_Subscriber,_util_isNumeric,_util_isScheduler PURE_IMPORTS_END */ @@ -31089,19 +30727,19 @@ function dispatchWindowClose(state) { /***/ }), -/* 356 */ +/* 352 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return windowToggle; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(171); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(175); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(167); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(171); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_Subject,_Subscription,_util_tryCatch,_util_errorObject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -31235,18 +30873,18 @@ var WindowToggleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 357 */ +/* 353 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return windowWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(182); -/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(174); -/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(175); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(178); +/* harmony import */ var _util_tryCatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(170); +/* harmony import */ var _util_errorObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(171); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_Subject,_util_tryCatch,_util_errorObject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -31334,15 +30972,15 @@ var WindowSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 358 */ +/* 354 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return withLatestFrom; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(166); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(224); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(225); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(220); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(221); /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -31429,13 +31067,13 @@ var WithLatestFromSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 359 */ +/* 355 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return zip; }); -/* harmony import */ var _observable_zip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(260); +/* harmony import */ var _observable_zip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(256); /** PURE_IMPORTS_START _observable_zip PURE_IMPORTS_END */ function zip() { @@ -31451,13 +31089,13 @@ function zip() { /***/ }), -/* 360 */ +/* 356 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return zipAll; }); -/* harmony import */ var _observable_zip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(260); +/* harmony import */ var _observable_zip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(256); /** PURE_IMPORTS_START _observable_zip PURE_IMPORTS_END */ function zipAll(project) { @@ -31467,7 +31105,7 @@ function zipAll(project) { /***/ }), -/* 361 */ +/* 357 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -31525,15 +31163,15 @@ var _chalk = __webpack_require__(2); var _chalk2 = _interopRequireDefault(_chalk); -var _indentString = __webpack_require__(362); +var _indentString = __webpack_require__(358); var _indentString2 = _interopRequireDefault(_indentString); -var _wrapAnsi = __webpack_require__(363); +var _wrapAnsi = __webpack_require__(359); var _wrapAnsi2 = _interopRequireDefault(_wrapAnsi); -var _config = __webpack_require__(135); +var _config = __webpack_require__(132); var _errors = __webpack_require__(52); @@ -31541,7 +31179,7 @@ var _log = __webpack_require__(33); var _projects = __webpack_require__(35); -var _projects_tree = __webpack_require__(370); +var _projects_tree = __webpack_require__(366); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -31573,7 +31211,7 @@ function toArray(value) { } /***/ }), -/* 362 */ +/* 358 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -31607,13 +31245,13 @@ module.exports = (str, count, opts) => { /***/ }), -/* 363 */ +/* 359 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringWidth = __webpack_require__(364); -const stripAnsi = __webpack_require__(368); +const stringWidth = __webpack_require__(360); +const stripAnsi = __webpack_require__(364); const ESCAPES = new Set([ '\u001B', @@ -31807,13 +31445,13 @@ module.exports = (str, cols, opts) => { /***/ }), -/* 364 */ +/* 360 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stripAnsi = __webpack_require__(365); -const isFullwidthCodePoint = __webpack_require__(367); +const stripAnsi = __webpack_require__(361); +const isFullwidthCodePoint = __webpack_require__(363); module.exports = str => { if (typeof str !== 'string' || str.length === 0) { @@ -31850,18 +31488,18 @@ module.exports = str => { /***/ }), -/* 365 */ +/* 361 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(366); +const ansiRegex = __webpack_require__(362); module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 366 */ +/* 362 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -31878,7 +31516,7 @@ module.exports = () => { /***/ }), -/* 367 */ +/* 363 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -31931,18 +31569,18 @@ module.exports = x => { /***/ }), -/* 368 */ +/* 364 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(369); +const ansiRegex = __webpack_require__(365); module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 369 */ +/* 365 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -31959,7 +31597,7 @@ module.exports = () => { /***/ }), -/* 370 */ +/* 366 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -32101,7 +31739,7 @@ function addProjectToTree(tree, pathParts, project) { } /***/ }), -/* 371 */ +/* 367 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -32111,7 +31749,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _build_production_projects = __webpack_require__(372); +var _build_production_projects = __webpack_require__(368); Object.defineProperty(exports, 'buildProductionProjects', { enumerable: true, @@ -32120,7 +31758,7 @@ Object.defineProperty(exports, 'buildProductionProjects', { } }); -var _prepare_project_dependencies = __webpack_require__(591); +var _prepare_project_dependencies = __webpack_require__(547); Object.defineProperty(exports, 'prepareExternalProjectDependencies', { enumerable: true, @@ -32130,7 +31768,7 @@ Object.defineProperty(exports, 'prepareExternalProjectDependencies', { }); /***/ }), -/* 372 */ +/* 368 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -32254,17 +31892,17 @@ let copyToBuild = (() => { }; })(); -var _cpy = __webpack_require__(373); +var _cpy = __webpack_require__(369); var _cpy2 = _interopRequireDefault(_cpy); -var _del = __webpack_require__(137); +var _del = __webpack_require__(134); var _del2 = _interopRequireDefault(_del); var _path = __webpack_require__(16); -var _config = __webpack_require__(135); +var _config = __webpack_require__(132); var _fs = __webpack_require__(20); @@ -32296,17 +31934,17 @@ function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, a */ /***/ }), -/* 373 */ +/* 369 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const EventEmitter = __webpack_require__(45); const path = __webpack_require__(16); -const arrify = __webpack_require__(374); -const globby = __webpack_require__(375); -const cpFile = __webpack_require__(582); -const CpyError = __webpack_require__(590); +const arrify = __webpack_require__(370); +const globby = __webpack_require__(371); +const cpFile = __webpack_require__(539); +const CpyError = __webpack_require__(546); const preprocessSrcPath = (srcPath, options) => options.cwd ? path.resolve(options.cwd, srcPath) : srcPath; @@ -32405,7 +32043,7 @@ module.exports = (src, dest, options = {}) => { /***/ }), -/* 374 */ +/* 370 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -32420,16 +32058,16 @@ module.exports = function (val) { /***/ }), -/* 375 */ +/* 371 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const arrayUnion = __webpack_require__(141); +const arrayUnion = __webpack_require__(138); const glob = __webpack_require__(36); -const fastGlob = __webpack_require__(376); -const dirGlob = __webpack_require__(577); -const gitignore = __webpack_require__(578); +const fastGlob = __webpack_require__(372); +const dirGlob = __webpack_require__(535); +const gitignore = __webpack_require__(536); const DEFAULT_FILTER = () => false; @@ -32555,10 +32193,10 @@ module.exports.gitignore = gitignore; /***/ }), -/* 376 */ +/* 372 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(377); +const pkg = __webpack_require__(373); module.exports = pkg.async; module.exports.default = pkg.async; @@ -32569,19 +32207,19 @@ module.exports.stream = pkg.stream; /***/ }), -/* 377 */ +/* 373 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(378); -var optionsManager = __webpack_require__(379); -var taskManager = __webpack_require__(380); -var reader_async_1 = __webpack_require__(556); -var reader_stream_1 = __webpack_require__(575); -var reader_sync_1 = __webpack_require__(576); -var arrayUtils = __webpack_require__(572); +var merge2 = __webpack_require__(374); +var optionsManager = __webpack_require__(375); +var taskManager = __webpack_require__(376); +var reader_async_1 = __webpack_require__(514); +var reader_stream_1 = __webpack_require__(533); +var reader_sync_1 = __webpack_require__(534); +var arrayUtils = __webpack_require__(530); /** * Returns a set of works based on provided tasks and class of the reader. */ @@ -32619,7 +32257,7 @@ exports.stream = stream; /***/ }), -/* 378 */ +/* 374 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -32733,7 +32371,7 @@ function pauseStreams (streams, options) { /***/ }), -/* 379 */ +/* 375 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -32768,14 +32406,14 @@ exports.prepare = prepare; /***/ }), -/* 380 */ +/* 376 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var objectUtils = __webpack_require__(381); -var patternUtils = __webpack_require__(382); +var objectUtils = __webpack_require__(377); +var patternUtils = __webpack_require__(378); /** * Returns grouped patterns by base directory of each pattern. */ @@ -32887,7 +32525,7 @@ exports.generate = generate; /***/ }), -/* 381 */ +/* 377 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -32900,7 +32538,7 @@ exports.values = values; /***/ }), -/* 382 */ +/* 378 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -32916,8 +32554,8 @@ var __values = (this && this.__values) || function (o) { }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var globParent = __webpack_require__(383); -var micromatch = __webpack_require__(387); +var globParent = __webpack_require__(379); +var micromatch = __webpack_require__(383); var GLOBSTAR = '**'; /** * Convert a windows «path» to a unix-style «path». @@ -33050,15 +32688,15 @@ exports.match = match; /***/ }), -/* 383 */ +/* 379 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(16); -var isglob = __webpack_require__(384); -var pathDirname = __webpack_require__(386); +var isglob = __webpack_require__(380); +var pathDirname = __webpack_require__(382); var isWin32 = __webpack_require__(11).platform() === 'win32'; module.exports = function globParent(str) { @@ -33081,7 +32719,7 @@ module.exports = function globParent(str) { /***/ }), -/* 384 */ +/* 380 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -33091,7 +32729,7 @@ module.exports = function globParent(str) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(385); +var isExtglob = __webpack_require__(381); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { @@ -33112,7 +32750,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 385 */ +/* 381 */ /***/ (function(module, exports) { /*! @@ -33138,7 +32776,7 @@ module.exports = function isExtglob(str) { /***/ }), -/* 386 */ +/* 382 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -33288,7 +32926,7 @@ module.exports.win32 = win32; /***/ }), -/* 387 */ +/* 383 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -33299,18 +32937,18 @@ module.exports.win32 = win32; */ var util = __webpack_require__(29); -var braces = __webpack_require__(388); -var toRegex = __webpack_require__(389); -var extend = __webpack_require__(398); +var braces = __webpack_require__(384); +var toRegex = __webpack_require__(385); +var extend = __webpack_require__(394); /** * Local dependencies */ -var compilers = __webpack_require__(524); -var parsers = __webpack_require__(552); -var cache = __webpack_require__(553); -var utils = __webpack_require__(554); +var compilers = __webpack_require__(488); +var parsers = __webpack_require__(510); +var cache = __webpack_require__(511); +var utils = __webpack_require__(512); var MAX_LENGTH = 1024 * 64; /** @@ -34174,7 +33812,7 @@ module.exports = micromatch; /***/ }), -/* 388 */ +/* 384 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -34184,19 +33822,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(389); -var unique = __webpack_require__(401); -var extend = __webpack_require__(398); -var define = __webpack_require__(402); +var toRegex = __webpack_require__(385); +var unique = __webpack_require__(397); +var extend = __webpack_require__(394); /** * Local dependencies */ -var compilers = __webpack_require__(409); -var parsers = __webpack_require__(424); -var Braces = __webpack_require__(427); -var utils = __webpack_require__(410); +var compilers = __webpack_require__(398); +var parsers = __webpack_require__(413); +var Braces = __webpack_require__(423); +var utils = __webpack_require__(399); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -34299,8 +33936,9 @@ braces.create = function(pattern, options) { throw new TypeError('expected a string'); } - if (pattern.length >= MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); + var maxLength = (options && options.maxLength) || MAX_LENGTH; + if (pattern.length >= maxLength) { + throw new Error('expected pattern to be less than ' + maxLength + ' characters'); } function create() { @@ -34334,7 +33972,11 @@ braces.create = function(pattern, options) { arr = unique(arr); } - define(arr, 'result', result); + Object.defineProperty(arr, 'result', { + enumerable: false, + value: result + }); + return arr; } @@ -34361,8 +34003,9 @@ braces.makeRe = function(pattern, options) { throw new TypeError('expected a string'); } - if (pattern.length >= MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); + var maxLength = (options && options.maxLength) || MAX_LENGTH; + if (pattern.length >= maxLength) { + throw new Error('expected pattern to be less than ' + maxLength + ' characters'); } function makeRe() { @@ -34494,15 +34137,15 @@ module.exports = braces; /***/ }), -/* 389 */ +/* 385 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(390); -var extend = __webpack_require__(398); -var not = __webpack_require__(400); +var define = __webpack_require__(386); +var extend = __webpack_require__(394); +var not = __webpack_require__(396); var MAX_LENGTH = 1024 * 64; /** @@ -34649,7 +34292,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 390 */ +/* 386 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -34662,7 +34305,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(391); +var isDescriptor = __webpack_require__(387); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -34687,7 +34330,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 391 */ +/* 387 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -34700,9 +34343,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(392); -var isAccessor = __webpack_require__(393); -var isData = __webpack_require__(396); +var typeOf = __webpack_require__(388); +var isAccessor = __webpack_require__(389); +var isData = __webpack_require__(392); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -34716,7 +34359,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 392 */ +/* 388 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -34869,7 +34512,7 @@ function isBuffer(val) { /***/ }), -/* 393 */ +/* 389 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -34882,7 +34525,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(394); +var typeOf = __webpack_require__(390); // accessor descriptor properties var accessor = { @@ -34945,10 +34588,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 394 */ +/* 390 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(395); +var isBuffer = __webpack_require__(391); var toString = Object.prototype.toString; /** @@ -35067,7 +34710,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 395 */ +/* 391 */ /***/ (function(module, exports) { /*! @@ -35094,7 +34737,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 396 */ +/* 392 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -35107,7 +34750,7 @@ function isSlowBuffer (obj) { -var typeOf = __webpack_require__(397); +var typeOf = __webpack_require__(393); // data descriptor properties var data = { @@ -35156,10 +34799,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 397 */ +/* 393 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(395); +var isBuffer = __webpack_require__(391); var toString = Object.prototype.toString; /** @@ -35278,13 +34921,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 398 */ +/* 394 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(399); +var isObject = __webpack_require__(395); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -35318,7 +34961,7 @@ function hasOwn(obj, key) { /***/ }), -/* 399 */ +/* 395 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -35338,13 +34981,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 400 */ +/* 396 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(398); +var extend = __webpack_require__(394); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -35411,7 +35054,7 @@ module.exports = toRegex; /***/ }), -/* 401 */ +/* 397 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -35461,2117 +35104,1521 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 402 */ +/* 398 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * define-property - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ +var utils = __webpack_require__(399); -var isDescriptor = __webpack_require__(403); +module.exports = function(braces, options) { + braces.compiler -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } + /** + * bos + */ - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } + .set('bos', function() { + if (this.output) return; + this.ast.queue = isEscaped(this.ast) ? [this.ast.val] : []; + this.ast.count = 1; + }) - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } + /** + * Square brackets + */ - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; + .set('bracket', function(node) { + var close = node.close; + var open = !node.escaped ? '[' : '\\['; + var negated = node.negated; + var inner = node.inner; + inner = inner.replace(/\\(?=[\\\w]|$)/g, '\\\\'); + if (inner === ']-') { + inner = '\\]\\-'; + } -/***/ }), -/* 403 */ -/***/ (function(module, exports, __webpack_require__) { + if (negated && inner.indexOf('.') === -1) { + inner += '.'; + } + if (negated && inner.indexOf('/') === -1) { + inner += '/'; + } -"use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ + var val = open + negated + inner + close; + var queue = node.parent.queue; + var last = utils.arrayify(queue.pop()); + queue.push(utils.join(last, val)); + queue.push.apply(queue, []); + }) + /** + * Brace + */ -var typeOf = __webpack_require__(404); -var isAccessor = __webpack_require__(405); -var isData = __webpack_require__(407); + .set('brace', function(node) { + node.queue = isEscaped(node) ? [node.val] : []; + node.count = 1; + return this.mapVisit(node.nodes); + }) -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; + /** + * Open + */ + .set('brace.open', function(node) { + node.parent.open = node.val; + }) -/***/ }), -/* 404 */ -/***/ (function(module, exports) { + /** + * Inner + */ -var toString = Object.prototype.toString; + .set('text', function(node) { + var queue = node.parent.queue; + var escaped = node.escaped; + var segs = [node.val]; -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; + if (node.optimize === false) { + options = utils.extend({}, options, {optimize: false}); + } - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } + if (node.multiplier > 1) { + node.parent.count *= node.multiplier; + } - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; + if (options.quantifiers === true && utils.isQuantifier(node.val)) { + escaped = true; - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; + } else if (node.val.length > 1) { + if (isType(node.parent, 'brace') && !isEscaped(node)) { + var expanded = utils.expand(node.val, options); + segs = expanded.segs; - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; + if (expanded.isOptimized) { + node.parent.isOptimized = true; + } - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; + // if nothing was expanded, we probably have a literal brace + if (!segs.length) { + var val = (expanded.val || node.val); + if (options.unescape !== false) { + // unescape unexpanded brace sequence/set separators + val = val.replace(/\\([,.])/g, '$1'); + // strip quotes + val = val.replace(/["'`]/g, ''); + } - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; + segs = [val]; + escaped = true; + } + } - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } + } else if (node.val === ',') { + if (options.expand) { + node.parent.queue.push(['']); + segs = ['']; + } else { + segs = ['|']; + } + } else { + escaped = true; + } - if (isGeneratorObj(val)) { - return 'generator'; - } + if (escaped && isType(node.parent, 'brace')) { + if (node.parent.nodes.length <= 4 && node.parent.count === 1) { + node.parent.escaped = true; + } else if (node.parent.length <= 3) { + node.parent.escaped = true; + } + } - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } + if (!hasQueue(node.parent)) { + node.parent.queue = segs; + return; + } - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; + var last = utils.arrayify(queue.pop()); + if (node.parent.count > 1 && options.expand) { + last = multiply(last, node.parent.count); + node.parent.count = 1; + } -function ctorName(val) { - return val.constructor ? val.constructor.name : null; -} + queue.push(utils.join(utils.flatten(last), segs.shift())); + queue.push.apply(queue, segs); + }) -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} + /** + * Close + */ -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} + .set('brace.close', function(node) { + var queue = node.parent.queue; + var prev = node.parent.parent; + var last = prev.queue.pop(); + var open = node.parent.open; + var close = node.val; -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} + if (open && close && isOptimized(node, options)) { + open = '('; + close = ')'; + } -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} + // if a close brace exists, and the previous segment is one character + // don't wrap the result in braces or parens + var ele = utils.last(queue); + if (node.parent.count > 1 && options.expand) { + ele = multiply(queue.pop(), node.parent.count); + node.parent.count = 1; + queue.push(ele); + } -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} + if (close && typeof ele === 'string' && ele.length === 1) { + open = ''; + close = ''; + } -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} + if ((isLiteralBrace(node, options) || noInner(node)) && !node.parent.hasEmpty) { + queue.push(utils.join(open, queue.pop() || '')); + queue = utils.flatten(utils.join(queue, close)); + } -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } - } - return false; -} + if (typeof last === 'undefined') { + prev.queue = [queue]; + } else { + prev.queue.push(utils.flatten(utils.join(last, queue))); + } + }) -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ + /** + * eos + */ -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; -} + .set('eos', function(node) { + if (this.input) return; + if (options.optimize !== false) { + this.output = utils.last(utils.flatten(this.ast.queue)); + } else if (Array.isArray(utils.last(this.ast.queue))) { + this.output = utils.flatten(this.ast.queue.pop()); + } else { + this.output = utils.flatten(this.ast.queue); + } -/***/ }), -/* 405 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ + if (node.parent.count > 1 && options.expand) { + this.output = multiply(this.output, node.parent.count); + } + this.output = utils.arrayify(this.output); + this.ast.queue = []; + }); +}; -var typeOf = __webpack_require__(406); +/** + * Multiply the segments in the current brace level + */ -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; +function multiply(queue, n, options) { + return utils.flatten(utils.repeat(utils.arrayify(queue), n)); +} -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } +/** + * Return true if `node` is escaped + */ - if (typeOf(obj) !== 'object') { - return false; - } +function isEscaped(node) { + return node.escaped === true; +} - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } +/** + * Returns true if regex parens should be used for sets. If the parent `type` + * is not `brace`, then we're on a root node, which means we should never + * expand segments and open/close braces should be `{}` (since this indicates + * a brace is missing from the set) + */ - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } +function isOptimized(node, options) { + if (node.parent.isOptimized) return true; + return isType(node.parent, 'brace') + && !isEscaped(node.parent) + && options.expand !== true; +} - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } +/** + * Returns true if the value in `node` should be wrapped in a literal brace. + * @return {Boolean} + */ - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } +function isLiteralBrace(node, options) { + return isEscaped(node.parent) || options.optimize !== false; +} - if (typeOf(obj[key]) === accessor[key]) { - continue; - } +/** + * Returns true if the given `node` does not have an inner value. + * @return {Boolean} + */ - if (typeof obj[key] !== 'undefined') { - return false; - } +function noInner(node, type) { + if (node.parent.queue.length === 1) { + return true; } - return true; + var nodes = node.parent.nodes; + return nodes.length === 3 + && isType(nodes[0], 'brace.open') + && !isType(nodes[1], 'text') + && isType(nodes[2], 'brace.close'); } -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); +/** + * Returns true if the given `node` is the given `type` + * @return {Boolean} + */ + +function isType(node, type) { + return typeof node !== 'undefined' && node.type === type; } /** - * Expose `isAccessorDescriptor` + * Returns true if the given `node` has a non-empty queue. + * @return {Boolean} */ -module.exports = isAccessorDescriptor; +function hasQueue(node) { + return Array.isArray(node.queue) && node.queue.length; +} /***/ }), -/* 406 */ -/***/ (function(module, exports) { +/* 399 */ +/***/ (function(module, exports, __webpack_require__) { -var toString = Object.prototype.toString; +"use strict"; -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } +var splitString = __webpack_require__(400); +var utils = module.exports; - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; +/** + * Module dependencies + */ - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; +utils.extend = __webpack_require__(394); +utils.flatten = __webpack_require__(406); +utils.isObject = __webpack_require__(404); +utils.fillRange = __webpack_require__(407); +utils.repeat = __webpack_require__(412); +utils.unique = __webpack_require__(397); - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; +utils.define = function(obj, key, val) { + Object.defineProperty(obj, key, { + writable: true, + configurable: true, + enumerable: false, + value: val + }); +}; - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; +/** + * Returns true if the given string contains only empty brace sets. + */ - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; +utils.isEmptySets = function(str) { + return /^(?:\{,\})+$/.test(str); +}; - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } +/** + * Returns true if the given string contains only empty brace sets. + */ - if (isGeneratorObj(val)) { - return 'generator'; +utils.isQuotedString = function(str) { + var open = str.charAt(0); + if (open === '\'' || open === '"' || open === '`') { + return str.slice(-1) === open; } + return false; +}; - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } +/** + * Create the key to use for memoization. The unique key is generated + * by iterating over the options and concatenating key-value pairs + * to the pattern string. + */ - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); +utils.createKey = function(pattern, options) { + var id = pattern; + if (typeof options === 'undefined') { + return id; + } + var keys = Object.keys(options); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + id += ';' + key + '=' + String(options[key]); + } + return id; }; -function ctorName(val) { - return val.constructor ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} +/** + * Normalize options + */ -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} +utils.createOptions = function(options) { + var opts = utils.extend.apply(null, arguments); + if (typeof opts.expand === 'boolean') { + opts.optimize = !opts.expand; + } + if (typeof opts.optimize === 'boolean') { + opts.expand = !opts.optimize; + } + if (opts.optimize === true) { + opts.makeRe = true; + } + return opts; +}; -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} +/** + * Join patterns in `a` to patterns in `b` + */ -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} +utils.join = function(a, b, options) { + options = options || {}; + a = utils.arrayify(a); + b = utils.arrayify(b); -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} + if (!a.length) return b; + if (!b.length) return a; -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} + var len = a.length; + var idx = -1; + var arr = []; -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; + while (++idx < len) { + var val = a[idx]; + if (Array.isArray(val)) { + for (var i = 0; i < val.length; i++) { + val[i] = utils.join(val[i], b, options); + } + arr.push(val); + continue; } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; + + for (var j = 0; j < b.length; j++) { + var bval = b[j]; + + if (Array.isArray(bval)) { + arr.push(utils.join(val, bval, options)); + } else { + arr.push(val + bval); + } } } - return false; -} + return arr; +}; /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * Split the given string on `,` if not escaped. */ -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); +utils.split = function(str, options) { + var opts = utils.extend({sep: ','}, options); + if (typeof opts.keepQuotes !== 'boolean') { + opts.keepQuotes = true; } - return false; -} - - -/***/ }), -/* 407 */ -/***/ (function(module, exports, __webpack_require__) { + if (opts.unescape === false) { + opts.keepEscaping = true; + } + return splitString(str, opts, utils.escapeBrackets(opts)); +}; -"use strict"; -/*! - * is-data-descriptor +/** + * Expand ranges or sets in the given `pattern`. * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * @param {String} `str` + * @param {Object} `options` + * @return {Object} */ +utils.expand = function(str, options) { + var opts = utils.extend({rangeLimit: 10000}, options); + var segs = utils.split(str, opts); + var tok = { segs: segs }; - -var typeOf = __webpack_require__(408); - -module.exports = function isDataDescriptor(obj, prop) { - // data descriptor properties - var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' - }; - - if (typeOf(obj) !== 'object') { - return false; + if (utils.isQuotedString(str)) { + return tok; } - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; + if (opts.rangeLimit === true) { + opts.rangeLimit = 10000; } - if (!('value' in obj) && !('writable' in obj)) { - return false; - } + if (segs.length > 1) { + if (opts.optimize === false) { + tok.val = segs[0]; + return tok; + } - for (var key in obj) { - if (key === 'value') continue; + tok.segs = utils.stringifyArray(tok.segs); + } else if (segs.length === 1) { + var arr = str.split('..'); - if (!data.hasOwnProperty(key)) { - continue; + if (arr.length === 1) { + tok.val = tok.segs[tok.segs.length - 1] || tok.val || str; + tok.segs = []; + return tok; } - if (typeOf(obj[key]) === data[key]) { - continue; + if (arr.length === 2 && arr[0] === arr[1]) { + tok.escaped = true; + tok.val = arr[0]; + tok.segs = []; + return tok; } - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -}; + if (arr.length > 1) { + if (opts.optimize !== false) { + opts.optimize = true; + delete opts.expand; + } + if (opts.optimize !== true) { + var min = Math.min(arr[0], arr[1]); + var max = Math.max(arr[0], arr[1]); + var step = arr[2] || 1; -/***/ }), -/* 408 */ -/***/ (function(module, exports) { + if (opts.rangeLimit !== false && ((max - min) / step >= opts.rangeLimit)) { + throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); + } + } -var toString = Object.prototype.toString; + arr.push(opts); + tok.segs = utils.fillRange.apply(null, arr); -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; + if (!tok.segs.length) { + tok.escaped = true; + tok.val = str; + return tok; + } - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; + if (opts.optimize === true) { + tok.segs = utils.stringifyArray(tok.segs); + } + + if (tok.segs === '') { + tok.val = str; + } else { + tok.val = tok.segs[0]; + } + return tok; + } + } else { + tok.val = str; } + return tok; +}; - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; +/** + * Ensure commas inside brackets and parens are not split. + * @param {Object} `tok` Token from the `split-string` module + * @return {undefined} + */ - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; +utils.escapeBrackets = function(options) { + return function(tok) { + if (tok.escaped && tok.val === 'b') { + tok.val = '\\b'; + return; + } - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; + if (tok.val !== '(' && tok.val !== '[') return; + var opts = utils.extend({}, options); + var brackets = []; + var parens = []; + var stack = []; + var val = tok.val; + var str = tok.str; + var i = tok.idx - 1; - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; + while (++i < str.length) { + var ch = str[i]; - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; + if (ch === '\\') { + val += (opts.keepEscaping === false ? '' : ch) + str[++i]; + continue; + } - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } + if (ch === '(') { + parens.push(ch); + stack.push(ch); + } - if (isGeneratorObj(val)) { - return 'generator'; - } + if (ch === '[') { + brackets.push(ch); + stack.push(ch); + } - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } + if (ch === ')') { + parens.pop(); + stack.pop(); + if (!stack.length) { + val += ch; + break; + } + } - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); + if (ch === ']') { + brackets.pop(); + stack.pop(); + if (!stack.length) { + val += ch; + break; + } + } + val += ch; + } + + tok.split = false; + tok.val = val.slice(1); + tok.idx = i; + }; }; -function ctorName(val) { - return val.constructor ? val.constructor.name : null; -} +/** + * Returns true if the given string looks like a regex quantifier + * @return {Boolean} + */ -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} +utils.isQuantifier = function(str) { + return /^(?:[0-9]?,[0-9]|[0-9],)$/.test(str); +}; -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} +/** + * Cast `val` to an array. + * @param {*} `val` + */ -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} +utils.stringifyArray = function(arr) { + return [utils.arrayify(arr).join('|')]; +}; -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} +/** + * Cast `val` to an array. + * @param {*} `val` + */ -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} +utils.arrayify = function(arr) { + if (typeof arr === 'undefined') { + return []; + } + if (typeof arr === 'string') { + return [arr]; + } + return arr; +}; -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} +/** + * Returns true if the given `str` is a non-empty string + * @return {Boolean} + */ -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } - } - return false; -} +utils.isString = function(str) { + return str != null && typeof str === 'string'; +}; /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * Get the last element from `array` + * @param {Array} `array` + * @return {*} */ -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; -} +utils.last = function(arr, n) { + return arr[arr.length - (n || 1)]; +}; + +utils.escapeRegex = function(str) { + return str.replace(/\\?([!^*?()[\]{}+?/])/g, '\\$1'); +}; /***/ }), -/* 409 */ +/* 400 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * split-string + * + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. + */ -var utils = __webpack_require__(410); - -module.exports = function(braces, options) { - braces.compiler - - /** - * bos - */ - - .set('bos', function() { - if (this.output) return; - this.ast.queue = isEscaped(this.ast) ? [this.ast.val] : []; - this.ast.count = 1; - }) - - /** - * Square brackets - */ - - .set('bracket', function(node) { - var close = node.close; - var open = !node.escaped ? '[' : '\\['; - var negated = node.negated; - var inner = node.inner; - - inner = inner.replace(/\\(?=[\\\w]|$)/g, '\\\\'); - if (inner === ']-') { - inner = '\\]\\-'; - } - - if (negated && inner.indexOf('.') === -1) { - inner += '.'; - } - if (negated && inner.indexOf('/') === -1) { - inner += '/'; - } - var val = open + negated + inner + close; - var queue = node.parent.queue; - var last = utils.arrayify(queue.pop()); +var extend = __webpack_require__(401); - queue.push(utils.join(last, val)); - queue.push.apply(queue, []); - }) +module.exports = function(str, options, fn) { + if (typeof str !== 'string') { + throw new TypeError('expected a string'); + } - /** - * Brace - */ + if (typeof options === 'function') { + fn = options; + options = null; + } - .set('brace', function(node) { - node.queue = isEscaped(node) ? [node.val] : []; - node.count = 1; - return this.mapVisit(node.nodes); - }) + // allow separator to be defined as a string + if (typeof options === 'string') { + options = { sep: options }; + } - /** - * Open - */ + var opts = extend({sep: '.'}, options); + var quotes = opts.quotes || ['"', "'", '`']; + var brackets; - .set('brace.open', function(node) { - node.parent.open = node.val; - }) + if (opts.brackets === true) { + brackets = { + '<': '>', + '(': ')', + '[': ']', + '{': '}' + }; + } else if (opts.brackets) { + brackets = opts.brackets; + } - /** - * Inner - */ + var tokens = []; + var stack = []; + var arr = ['']; + var sep = opts.sep; + var len = str.length; + var idx = -1; + var closeIdx; - .set('text', function(node) { - var queue = node.parent.queue; - var escaped = node.escaped; - var segs = [node.val]; + function expected() { + if (brackets && stack.length) { + return brackets[stack[stack.length - 1]]; + } + } - if (node.optimize === false) { - options = utils.extend({}, options, {optimize: false}); - } + while (++idx < len) { + var ch = str[idx]; + var next = str[idx + 1]; + var tok = { val: ch, idx: idx, arr: arr, str: str }; + tokens.push(tok); - if (node.multiplier > 1) { - node.parent.count *= node.multiplier; + if (ch === '\\') { + tok.val = keepEscaping(opts, str, idx) === true ? (ch + next) : next; + tok.escaped = true; + if (typeof fn === 'function') { + fn(tok); } + arr[arr.length - 1] += tok.val; + idx++; + continue; + } - if (options.quantifiers === true && utils.isQuantifier(node.val)) { - escaped = true; + if (brackets && brackets[ch]) { + stack.push(ch); + var e = expected(); + var i = idx + 1; - } else if (node.val.length > 1) { - if (isType(node.parent, 'brace') && !isEscaped(node)) { - var expanded = utils.expand(node.val, options); - segs = expanded.segs; + if (str.indexOf(e, i + 1) !== -1) { + while (stack.length && i < len) { + var s = str[++i]; + if (s === '\\') { + s++; + continue; + } - if (expanded.isOptimized) { - node.parent.isOptimized = true; + if (quotes.indexOf(s) !== -1) { + i = getClosingQuote(str, s, i + 1); + continue; } - // if nothing was expanded, we probably have a literal brace - if (!segs.length) { - var val = (expanded.val || node.val); - if (options.unescape !== false) { - // unescape unexpanded brace sequence/set separators - val = val.replace(/\\([,.])/g, '$1'); - // strip quotes - val = val.replace(/["'`]/g, ''); - } + e = expected(); + if (stack.length && str.indexOf(e, i + 1) === -1) { + break; + } - segs = [val]; - escaped = true; + if (brackets[s]) { + stack.push(s); + continue; } - } - } else if (node.val === ',') { - if (options.expand) { - node.parent.queue.push(['']); - segs = ['']; - } else { - segs = ['|']; + if (e === s) { + stack.pop(); + } } - } else { - escaped = true; } - if (escaped && isType(node.parent, 'brace')) { - if (node.parent.nodes.length <= 4 && node.parent.count === 1) { - node.parent.escaped = true; - } else if (node.parent.length <= 3) { - node.parent.escaped = true; - } + closeIdx = i; + if (closeIdx === -1) { + arr[arr.length - 1] += ch; + continue; } - if (!hasQueue(node.parent)) { - node.parent.queue = segs; - return; + ch = str.slice(idx, closeIdx + 1); + tok.val = ch; + tok.idx = idx = closeIdx; + } + + if (quotes.indexOf(ch) !== -1) { + closeIdx = getClosingQuote(str, ch, idx + 1); + if (closeIdx === -1) { + arr[arr.length - 1] += ch; + continue; } - var last = utils.arrayify(queue.pop()); - if (node.parent.count > 1 && options.expand) { - last = multiply(last, node.parent.count); - node.parent.count = 1; + if (keepQuotes(ch, opts) === true) { + ch = str.slice(idx, closeIdx + 1); + } else { + ch = str.slice(idx + 1, closeIdx); } - queue.push(utils.join(utils.flatten(last), segs.shift())); - queue.push.apply(queue, segs); - }) + tok.val = ch; + tok.idx = idx = closeIdx; + } - /** - * Close - */ + if (typeof fn === 'function') { + fn(tok, tokens); + ch = tok.val; + idx = tok.idx; + } - .set('brace.close', function(node) { - var queue = node.parent.queue; - var prev = node.parent.parent; - var last = prev.queue.pop(); - var open = node.parent.open; - var close = node.val; + if (tok.val === sep && tok.split !== false) { + arr.push(''); + continue; + } - if (open && close && isOptimized(node, options)) { - open = '('; - close = ')'; - } + arr[arr.length - 1] += tok.val; + } - // if a close brace exists, and the previous segment is one character - // don't wrap the result in braces or parens - var ele = utils.last(queue); - if (node.parent.count > 1 && options.expand) { - ele = multiply(queue.pop(), node.parent.count); - node.parent.count = 1; - queue.push(ele); - } + return arr; +}; - if (close && typeof ele === 'string' && ele.length === 1) { - open = ''; - close = ''; - } +function getClosingQuote(str, ch, i, brackets) { + var idx = str.indexOf(ch, i); + if (str.charAt(idx - 1) === '\\') { + return getClosingQuote(str, ch, idx + 1); + } + return idx; +} - if ((isLiteralBrace(node, options) || noInner(node)) && !node.parent.hasEmpty) { - queue.push(utils.join(open, queue.pop() || '')); - queue = utils.flatten(utils.join(queue, close)); - } +function keepQuotes(ch, opts) { + if (opts.keepDoubleQuotes === true && ch === '"') return true; + if (opts.keepSingleQuotes === true && ch === "'") return true; + return opts.keepQuotes; +} - if (typeof last === 'undefined') { - prev.queue = [queue]; - } else { - prev.queue.push(utils.flatten(utils.join(last, queue))); - } - }) +function keepEscaping(opts, str, idx) { + if (typeof opts.keepEscaping === 'function') { + return opts.keepEscaping(str, idx); + } + return opts.keepEscaping === true || str[idx + 1] === '\\'; +} - /** - * eos - */ - .set('eos', function(node) { - if (this.input) return; +/***/ }), +/* 401 */ +/***/ (function(module, exports, __webpack_require__) { - if (options.optimize !== false) { - this.output = utils.last(utils.flatten(this.ast.queue)); - } else if (Array.isArray(utils.last(this.ast.queue))) { - this.output = utils.flatten(this.ast.queue.pop()); - } else { - this.output = utils.flatten(this.ast.queue); - } +"use strict"; - if (node.parent.count > 1 && options.expand) { - this.output = multiply(this.output, node.parent.count); - } - this.output = utils.arrayify(this.output); - this.ast.queue = []; - }); +var isExtendable = __webpack_require__(402); +var assignSymbols = __webpack_require__(405); +module.exports = Object.assign || function(obj/*, objects*/) { + if (obj === null || typeof obj === 'undefined') { + throw new TypeError('Cannot convert undefined or null to object'); + } + if (!isObject(obj)) { + obj = {}; + } + for (var i = 1; i < arguments.length; i++) { + var val = arguments[i]; + if (isString(val)) { + val = toObject(val); + } + if (isObject(val)) { + assign(obj, val); + assignSymbols(obj, val); + } + } + return obj; }; -/** - * Multiply the segments in the current brace level - */ +function assign(a, b) { + for (var key in b) { + if (hasOwn(b, key)) { + a[key] = b[key]; + } + } +} -function multiply(queue, n, options) { - return utils.flatten(utils.repeat(utils.arrayify(queue), n)); +function isString(val) { + return (val && typeof val === 'string'); } -/** - * Return true if `node` is escaped - */ +function toObject(str) { + var obj = {}; + for (var i in str) { + obj[i] = str[i]; + } + return obj; +} -function isEscaped(node) { - return node.escaped === true; +function isObject(val) { + return (val && typeof val === 'object') || isExtendable(val); } /** - * Returns true if regex parens should be used for sets. If the parent `type` - * is not `brace`, then we're on a root node, which means we should never - * expand segments and open/close braces should be `{}` (since this indicates - * a brace is missing from the set) + * Returns true if the given `key` is an own property of `obj`. */ -function isOptimized(node, options) { - if (node.parent.isOptimized) return true; - return isType(node.parent, 'brace') - && !isEscaped(node.parent) - && options.expand !== true; +function hasOwn(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); } -/** - * Returns true if the value in `node` should be wrapped in a literal brace. - * @return {Boolean} - */ - -function isLiteralBrace(node, options) { - return isEscaped(node.parent) || options.optimize !== false; +function isEnum(obj, key) { + return Object.prototype.propertyIsEnumerable.call(obj, key); } -/** - * Returns true if the given `node` does not have an inner value. - * @return {Boolean} - */ -function noInner(node, type) { - if (node.parent.queue.length === 1) { - return true; - } - var nodes = node.parent.nodes; - return nodes.length === 3 - && isType(nodes[0], 'brace.open') - && !isType(nodes[1], 'text') - && isType(nodes[2], 'brace.close'); -} +/***/ }), +/* 402 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Returns true if the given `node` is the given `type` - * @return {Boolean} +"use strict"; +/*! + * is-extendable + * + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. */ -function isType(node, type) { - return typeof node !== 'undefined' && node.type === type; -} -/** - * Returns true if the given `node` has a non-empty queue. - * @return {Boolean} - */ -function hasQueue(node) { - return Array.isArray(node.queue) && node.queue.length; -} +var isPlainObject = __webpack_require__(403); + +module.exports = function isExtendable(val) { + return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); +}; /***/ }), -/* 410 */ +/* 403 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - - -var splitString = __webpack_require__(411); -var utils = module.exports; - -/** - * Module dependencies +/*! + * is-plain-object + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.define = __webpack_require__(402); -utils.extend = __webpack_require__(398); -utils.flatten = __webpack_require__(417); -utils.isObject = __webpack_require__(415); -utils.fillRange = __webpack_require__(418); -utils.repeat = __webpack_require__(423); -utils.unique = __webpack_require__(401); -/** - * Returns true if the given string contains only empty brace sets. - */ -utils.isEmptySets = function(str) { - return /^(?:\{,\})+$/.test(str); -}; +var isObject = __webpack_require__(404); -/** - * Returns true if the given string contains only empty brace sets. - */ +function isObjectObject(o) { + return isObject(o) === true + && Object.prototype.toString.call(o) === '[object Object]'; +} -utils.isQuotedString = function(str) { - var open = str.charAt(0); - if (open === '\'' || open === '"' || open === '`') { - return str.slice(-1) === open; - } - return false; -}; +module.exports = function isPlainObject(o) { + var ctor,prot; -/** - * Create the key to use for memoization. The unique key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ + if (isObjectObject(o) === false) return false; -utils.createKey = function(pattern, options) { - var id = pattern; - if (typeof options === 'undefined') { - return id; - } - var keys = Object.keys(options); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - id += ';' + key + '=' + String(options[key]); - } - return id; -}; + // If has modified constructor + ctor = o.constructor; + if (typeof ctor !== 'function') return false; -/** - * Normalize options - */ + // If has modified prototype + prot = ctor.prototype; + if (isObjectObject(prot) === false) return false; -utils.createOptions = function(options) { - var opts = utils.extend.apply(null, arguments); - if (typeof opts.expand === 'boolean') { - opts.optimize = !opts.expand; - } - if (typeof opts.optimize === 'boolean') { - opts.expand = !opts.optimize; - } - if (opts.optimize === true) { - opts.makeRe = true; + // If constructor does not have an Object-specific method + if (prot.hasOwnProperty('isPrototypeOf') === false) { + return false; } - return opts; -}; -/** - * Join patterns in `a` to patterns in `b` - */ + // Most likely a plain Object + return true; +}; -utils.join = function(a, b, options) { - options = options || {}; - a = utils.arrayify(a); - b = utils.arrayify(b); - if (!a.length) return b; - if (!b.length) return a; +/***/ }), +/* 404 */ +/***/ (function(module, exports, __webpack_require__) { - var len = a.length; - var idx = -1; - var arr = []; +"use strict"; +/*! + * isobject + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ - while (++idx < len) { - var val = a[idx]; - if (Array.isArray(val)) { - for (var i = 0; i < val.length; i++) { - val[i] = utils.join(val[i], b, options); - } - arr.push(val); - continue; - } - for (var j = 0; j < b.length; j++) { - var bval = b[j]; - if (Array.isArray(bval)) { - arr.push(utils.join(val, bval, options)); - } else { - arr.push(val + bval); - } - } - } - return arr; +module.exports = function isObject(val) { + return val != null && typeof val === 'object' && Array.isArray(val) === false; }; -/** - * Split the given string on `,` if not escaped. - */ -utils.split = function(str, options) { - var opts = utils.extend({sep: ','}, options); - if (typeof opts.keepQuotes !== 'boolean') { - opts.keepQuotes = true; - } - if (opts.unescape === false) { - opts.keepEscaping = true; - } - return splitString(str, opts, utils.escapeBrackets(opts)); -}; +/***/ }), +/* 405 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Expand ranges or sets in the given `pattern`. +"use strict"; +/*! + * assign-symbols * - * @param {String} `str` - * @param {Object} `options` - * @return {Object} + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. */ -utils.expand = function(str, options) { - var opts = utils.extend({rangeLimit: 10000}, options); - var segs = utils.split(str, opts); - var tok = { segs: segs }; - if (utils.isQuotedString(str)) { - return tok; - } - if (opts.rangeLimit === true) { - opts.rangeLimit = 10000; +module.exports = function(receiver, objects) { + if (receiver === null || typeof receiver === 'undefined') { + throw new TypeError('expected first argument to be an object.'); } - if (segs.length > 1) { - if (opts.optimize === false) { - tok.val = segs[0]; - return tok; - } - - tok.segs = utils.stringifyArray(tok.segs); - } else if (segs.length === 1) { - var arr = str.split('..'); - - if (arr.length === 1) { - tok.val = tok.segs[tok.segs.length - 1] || tok.val || str; - tok.segs = []; - return tok; - } - - if (arr.length === 2 && arr[0] === arr[1]) { - tok.escaped = true; - tok.val = arr[0]; - tok.segs = []; - return tok; - } - - if (arr.length > 1) { - if (opts.optimize !== false) { - opts.optimize = true; - delete opts.expand; - } - - if (opts.optimize !== true) { - var min = Math.min(arr[0], arr[1]); - var max = Math.max(arr[0], arr[1]); - var step = arr[2] || 1; + if (typeof objects === 'undefined' || typeof Symbol === 'undefined') { + return receiver; + } - if (opts.rangeLimit !== false && ((max - min) / step >= opts.rangeLimit)) { - throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); - } - } + if (typeof Object.getOwnPropertySymbols !== 'function') { + return receiver; + } - arr.push(opts); - tok.segs = utils.fillRange.apply(null, arr); + var isEnumerable = Object.prototype.propertyIsEnumerable; + var target = Object(receiver); + var len = arguments.length, i = 0; - if (!tok.segs.length) { - tok.escaped = true; - tok.val = str; - return tok; - } + while (++i < len) { + var provider = Object(arguments[i]); + var names = Object.getOwnPropertySymbols(provider); - if (opts.optimize === true) { - tok.segs = utils.stringifyArray(tok.segs); - } + for (var j = 0; j < names.length; j++) { + var key = names[j]; - if (tok.segs === '') { - tok.val = str; - } else { - tok.val = tok.segs[0]; + if (isEnumerable.call(provider, key)) { + target[key] = provider[key]; } - return tok; } - } else { - tok.val = str; } - return tok; + return target; }; -/** - * Ensure commas inside brackets and parens are not split. - * @param {Object} `tok` Token from the `split-string` module - * @return {undefined} + +/***/ }), +/* 406 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * arr-flatten + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.escapeBrackets = function(options) { - return function(tok) { - if (tok.escaped && tok.val === 'b') { - tok.val = '\\b'; - return; - } - if (tok.val !== '(' && tok.val !== '[') return; - var opts = utils.extend({}, options); - var brackets = []; - var parens = []; - var stack = []; - var val = tok.val; - var str = tok.str; - var i = tok.idx - 1; - while (++i < str.length) { - var ch = str[i]; +module.exports = function (arr) { + return flat(arr, []); +}; - if (ch === '\\') { - val += (opts.keepEscaping === false ? '' : ch) + str[++i]; - continue; - } +function flat(arr, res) { + var i = 0, cur; + var len = arr.length; + for (; i < len; i++) { + cur = arr[i]; + Array.isArray(cur) ? flat(cur, res) : res.push(cur); + } + return res; +} - if (ch === '(') { - parens.push(ch); - stack.push(ch); - } - if (ch === '[') { - brackets.push(ch); - stack.push(ch); - } +/***/ }), +/* 407 */ +/***/ (function(module, exports, __webpack_require__) { - if (ch === ')') { - parens.pop(); - stack.pop(); - if (!stack.length) { - val += ch; - break; - } - } +"use strict"; +/*! + * fill-range + * + * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Released under the MIT License. + */ - if (ch === ']') { - brackets.pop(); - stack.pop(); - if (!stack.length) { - val += ch; - break; - } - } - val += ch; - } - tok.split = false; - tok.val = val.slice(1); - tok.idx = i; - }; -}; + +var util = __webpack_require__(29); +var isNumber = __webpack_require__(408); +var extend = __webpack_require__(394); +var repeat = __webpack_require__(410); +var toRegex = __webpack_require__(411); /** - * Returns true if the given string looks like a regex quantifier - * @return {Boolean} + * Return a range of numbers or letters. + * + * @param {String} `start` Start of the range + * @param {String} `stop` End of the range + * @param {String} `step` Increment or decrement to use. + * @param {Function} `fn` Custom function to modify each element in the range. + * @return {Array} */ -utils.isQuantifier = function(str) { - return /^(?:[0-9]?,[0-9]|[0-9],)$/.test(str); -}; +function fillRange(start, stop, step, options) { + if (typeof start === 'undefined') { + return []; + } -/** - * Cast `val` to an array. - * @param {*} `val` - */ + if (typeof stop === 'undefined' || start === stop) { + // special case, for handling negative zero + var isString = typeof start === 'string'; + if (isNumber(start) && !toNumber(start)) { + return [isString ? '0' : 0]; + } + return [start]; + } -utils.stringifyArray = function(arr) { - return [utils.arrayify(arr).join('|')]; -}; + if (typeof step !== 'number' && typeof step !== 'string') { + options = step; + step = undefined; + } -/** - * Cast `val` to an array. - * @param {*} `val` - */ + if (typeof options === 'function') { + options = { transform: options }; + } -utils.arrayify = function(arr) { - if (typeof arr === 'undefined') { + var opts = extend({step: step}, options); + if (opts.step && !isValidNumber(opts.step)) { + if (opts.strictRanges === true) { + throw new TypeError('expected options.step to be a number'); + } return []; } - if (typeof arr === 'string') { - return [arr]; + + opts.isNumber = isValidNumber(start) && isValidNumber(stop); + if (!opts.isNumber && !isValid(start, stop)) { + if (opts.strictRanges === true) { + throw new RangeError('invalid range arguments: ' + util.inspect([start, stop])); + } + return []; } - return arr; -}; -/** - * Returns true if the given `str` is a non-empty string - * @return {Boolean} - */ + opts.isPadded = isPadded(start) || isPadded(stop); + opts.toString = opts.stringify + || typeof opts.step === 'string' + || typeof start === 'string' + || typeof stop === 'string' + || !opts.isNumber; -utils.isString = function(str) { - return str != null && typeof str === 'string'; -}; + if (opts.isPadded) { + opts.maxLength = Math.max(String(start).length, String(stop).length); + } -/** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} - */ + // support legacy minimatch/fill-range options + if (typeof opts.optimize === 'boolean') opts.toRegex = opts.optimize; + if (typeof opts.makeRe === 'boolean') opts.toRegex = opts.makeRe; + return expand(start, stop, opts); +} -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; +function expand(start, stop, options) { + var a = options.isNumber ? toNumber(start) : start.charCodeAt(0); + var b = options.isNumber ? toNumber(stop) : stop.charCodeAt(0); -utils.escapeRegex = function(str) { - return str.replace(/\\?([!^*?()\[\]{}+?/])/g, '\\$1'); -}; + var step = Math.abs(toNumber(options.step)) || 1; + if (options.toRegex && step === 1) { + return toRange(a, b, start, stop, options); + } + var zero = {greater: [], lesser: []}; + var asc = a < b; + var arr = new Array(Math.round((asc ? b - a : a - b) / step)); + var idx = 0; -/***/ }), -/* 411 */ -/***/ (function(module, exports, __webpack_require__) { + while (asc ? a <= b : a >= b) { + var val = options.isNumber ? a : String.fromCharCode(a); + if (options.toRegex && (val >= 0 || !options.isNumber)) { + zero.greater.push(val); + } else { + zero.lesser.push(Math.abs(val)); + } -"use strict"; -/*! - * split-string - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ + if (options.isPadded) { + val = zeros(val, options); + } + if (options.toString) { + val = String(val); + } + if (typeof options.transform === 'function') { + arr[idx++] = options.transform(val, a, b, step, idx, arr, options); + } else { + arr[idx++] = val; + } -var extend = __webpack_require__(412); + if (asc) { + a += step; + } else { + a -= step; + } + } -module.exports = function(str, options, fn) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); + if (options.toRegex === true) { + return toSequence(arr, zero, options); } + return arr; +} - if (typeof options === 'function') { - fn = options; - options = null; +function toRange(a, b, start, stop, options) { + if (options.isPadded) { + return toRegex(start, stop, options); } - // allow separator to be defined as a string - if (typeof options === 'string') { - options = { sep: options }; + if (options.isNumber) { + return toRegex(Math.min(a, b), Math.max(a, b), options); } - var opts = extend({sep: '.'}, options); - var quotes = opts.quotes || ['"', "'", '`']; - var brackets; + var start = String.fromCharCode(Math.min(a, b)); + var stop = String.fromCharCode(Math.max(a, b)); + return '[' + start + '-' + stop + ']'; +} - if (opts.brackets === true) { - brackets = { - '<': '>', - '(': ')', - '[': ']', - '{': '}' - }; - } else if (opts.brackets) { - brackets = opts.brackets; +function toSequence(arr, zeros, options) { + var greater = '', lesser = ''; + if (zeros.greater.length) { + greater = zeros.greater.join('|'); + } + if (zeros.lesser.length) { + lesser = '-(' + zeros.lesser.join('|') + ')'; } + var res = greater && lesser + ? greater + '|' + lesser + : greater || lesser; - var tokens = []; - var stack = []; - var arr = ['']; - var sep = opts.sep; - var len = str.length; - var idx = -1; - var closeIdx; - - function expected() { - if (brackets && stack.length) { - return brackets[stack[stack.length - 1]]; - } + if (options.capture) { + return '(' + res + ')'; } + return res; +} - while (++idx < len) { - var ch = str[idx]; - var next = str[idx + 1]; - var tok = { val: ch, idx: idx, arr: arr, str: str }; - tokens.push(tok); - - if (ch === '\\') { - tok.val = keepEscaping(opts, str, idx) === true ? (ch + next) : next; - tok.escaped = true; - if (typeof fn === 'function') { - fn(tok); - } - arr[arr.length - 1] += tok.val; - idx++; - continue; - } - - if (brackets && brackets[ch]) { - stack.push(ch); - var e = expected(); - var i = idx + 1; - - if (str.indexOf(e, i + 1) !== -1) { - while (stack.length && i < len) { - var s = str[++i]; - if (s === '\\') { - s++; - continue; - } - - if (quotes.indexOf(s) !== -1) { - i = getClosingQuote(str, s, i + 1); - continue; - } - - e = expected(); - if (stack.length && str.indexOf(e, i + 1) === -1) { - break; - } - - if (brackets[s]) { - stack.push(s); - continue; - } - - if (e === s) { - stack.pop(); - } - } - } - - closeIdx = i; - if (closeIdx === -1) { - arr[arr.length - 1] += ch; - continue; - } - - ch = str.slice(idx, closeIdx + 1); - tok.val = ch; - tok.idx = idx = closeIdx; - } - - if (quotes.indexOf(ch) !== -1) { - closeIdx = getClosingQuote(str, ch, idx + 1); - if (closeIdx === -1) { - arr[arr.length - 1] += ch; - continue; - } - - if (keepQuotes(ch, opts) === true) { - ch = str.slice(idx, closeIdx + 1); - } else { - ch = str.slice(idx + 1, closeIdx); - } - - tok.val = ch; - tok.idx = idx = closeIdx; - } - - if (typeof fn === 'function') { - fn(tok, tokens); - ch = tok.val; - idx = tok.idx; - } - - if (tok.val === sep && tok.split !== false) { - arr.push(''); - continue; +function zeros(val, options) { + if (options.isPadded) { + var str = String(val); + var len = str.length; + var dash = ''; + if (str.charAt(0) === '-') { + dash = '-'; + str = str.slice(1); } - - arr[arr.length - 1] += tok.val; + var diff = options.maxLength - len; + var pad = repeat('0', diff); + val = (dash + pad + str); } - - return arr; -}; - -function getClosingQuote(str, ch, i, brackets) { - var idx = str.indexOf(ch, i); - if (str.charAt(idx - 1) === '\\') { - return getClosingQuote(str, ch, idx + 1); + if (options.stringify) { + return String(val); } - return idx; -} - -function keepQuotes(ch, opts) { - if (opts.keepDoubleQuotes === true && ch === '"') return true; - if (opts.keepSingleQuotes === true && ch === "'") return true; - return opts.keepQuotes; + return val; } -function keepEscaping(opts, str, idx) { - if (typeof opts.keepEscaping === 'function') { - return opts.keepEscaping(str, idx); - } - return opts.keepEscaping === true || str[idx + 1] === '\\'; +function toNumber(val) { + return Number(val) || 0; } - -/***/ }), -/* 412 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(413); -var assignSymbols = __webpack_require__(416); - -module.exports = Object.assign || function(obj/*, objects*/) { - if (obj === null || typeof obj === 'undefined') { - throw new TypeError('Cannot convert undefined or null to object'); - } - if (!isObject(obj)) { - obj = {}; - } - for (var i = 1; i < arguments.length; i++) { - var val = arguments[i]; - if (isString(val)) { - val = toObject(val); - } - if (isObject(val)) { - assign(obj, val); - assignSymbols(obj, val); - } - } - return obj; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } +function isPadded(str) { + return /^-?0\d/.test(str); } -function isString(val) { - return (val && typeof val === 'string'); +function isValid(min, max) { + return (isValidNumber(min) || isValidLetter(min)) + && (isValidNumber(max) || isValidLetter(max)); } -function toObject(str) { - var obj = {}; - for (var i in str) { - obj[i] = str[i]; - } - return obj; +function isValidLetter(ch) { + return typeof ch === 'string' && ch.length === 1 && /^\w+$/.test(ch); } -function isObject(val) { - return (val && typeof val === 'object') || isExtendable(val); +function isValidNumber(n) { + return isNumber(n) && !/\./.test(n); } /** - * Returns true if the given `key` is an own property of `obj`. + * Expose `fillRange` + * @type {Function} */ -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -function isEnum(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); -} +module.exports = fillRange; /***/ }), -/* 413 */ +/* 408 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-extendable + * is-number * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. */ -var isPlainObject = __webpack_require__(414); +var typeOf = __webpack_require__(409); -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); +module.exports = function isNumber(num) { + var type = typeOf(num); + + if (type === 'string') { + if (!num.trim()) return false; + } else if (type !== 'number') { + return false; + } + + return (num - num + 1) >= 0; }; /***/ }), -/* 414 */ +/* 409 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; -/*! - * is-plain-object +var isBuffer = __webpack_require__(391); +var toString = Object.prototype.toString; + +/** + * Get the native `typeof` a value. * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. + * @param {*} `val` + * @return {*} Native javascript type */ +module.exports = function kindOf(val) { + // primitivies + if (typeof val === 'undefined') { + return 'undefined'; + } + if (val === null) { + return 'null'; + } + if (val === true || val === false || val instanceof Boolean) { + return 'boolean'; + } + if (typeof val === 'string' || val instanceof String) { + return 'string'; + } + if (typeof val === 'number' || val instanceof Number) { + return 'number'; + } + // functions + if (typeof val === 'function' || val instanceof Function) { + return 'function'; + } -var isObject = __webpack_require__(415); + // array + if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { + return 'array'; + } -function isObjectObject(o) { - return isObject(o) === true - && Object.prototype.toString.call(o) === '[object Object]'; -} + // check for instances of RegExp and Date before calling `toString` + if (val instanceof RegExp) { + return 'regexp'; + } + if (val instanceof Date) { + return 'date'; + } -module.exports = function isPlainObject(o) { - var ctor,prot; + // other objects + var type = toString.call(val); - if (isObjectObject(o) === false) return false; + if (type === '[object RegExp]') { + return 'regexp'; + } + if (type === '[object Date]') { + return 'date'; + } + if (type === '[object Arguments]') { + return 'arguments'; + } + if (type === '[object Error]') { + return 'error'; + } - // If has modified constructor - ctor = o.constructor; - if (typeof ctor !== 'function') return false; + // buffer + if (isBuffer(val)) { + return 'buffer'; + } - // If has modified prototype - prot = ctor.prototype; - if (isObjectObject(prot) === false) return false; + // es6: Map, WeakMap, Set, WeakSet + if (type === '[object Set]') { + return 'set'; + } + if (type === '[object WeakSet]') { + return 'weakset'; + } + if (type === '[object Map]') { + return 'map'; + } + if (type === '[object WeakMap]') { + return 'weakmap'; + } + if (type === '[object Symbol]') { + return 'symbol'; + } - // If constructor does not have an Object-specific method - if (prot.hasOwnProperty('isPrototypeOf') === false) { - return false; + // typed arrays + if (type === '[object Int8Array]') { + return 'int8array'; + } + if (type === '[object Uint8Array]') { + return 'uint8array'; + } + if (type === '[object Uint8ClampedArray]') { + return 'uint8clampedarray'; + } + if (type === '[object Int16Array]') { + return 'int16array'; + } + if (type === '[object Uint16Array]') { + return 'uint16array'; + } + if (type === '[object Int32Array]') { + return 'int32array'; + } + if (type === '[object Uint32Array]') { + return 'uint32array'; + } + if (type === '[object Float32Array]') { + return 'float32array'; + } + if (type === '[object Float64Array]') { + return 'float64array'; } - // Most likely a plain Object - return true; + // must be a plain object + return 'object'; }; /***/ }), -/* 415 */ +/* 410 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * isobject + * repeat-string * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. */ -module.exports = function isObject(val) { - return val != null && typeof val === 'object' && Array.isArray(val) === false; -}; - +/** + * Results cache + */ -/***/ }), -/* 416 */ -/***/ (function(module, exports, __webpack_require__) { +var res = ''; +var cache; -"use strict"; -/*! - * assign-symbols - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. +/** + * Expose `repeat` */ +module.exports = repeat; +/** + * Repeat the given `string` the specified `number` + * of times. + * + * **Example:** + * + * ```js + * var repeat = require('repeat-string'); + * repeat('A', 5); + * //=> AAAAA + * ``` + * + * @param {String} `string` The string to repeat + * @param {Number} `number` The number of times to repeat the string + * @return {String} Repeated string + * @api public + */ -module.exports = function(receiver, objects) { - if (receiver === null || typeof receiver === 'undefined') { - throw new TypeError('expected first argument to be an object.'); +function repeat(str, num) { + if (typeof str !== 'string') { + throw new TypeError('expected a string'); } - if (typeof objects === 'undefined' || typeof Symbol === 'undefined') { - return receiver; - } + // cover common, quick use cases + if (num === 1) return str; + if (num === 2) return str + str; - if (typeof Object.getOwnPropertySymbols !== 'function') { - return receiver; + var max = str.length * num; + if (cache !== str || typeof cache === 'undefined') { + cache = str; + res = ''; + } else if (res.length >= max) { + return res.substr(0, max); } - var isEnumerable = Object.prototype.propertyIsEnumerable; - var target = Object(receiver); - var len = arguments.length, i = 0; - - while (++i < len) { - var provider = Object(arguments[i]); - var names = Object.getOwnPropertySymbols(provider); - - for (var j = 0; j < names.length; j++) { - var key = names[j]; - - if (isEnumerable.call(provider, key)) { - target[key] = provider[key]; - } + while (max > res.length && num > 1) { + if (num & 1) { + res += str; } - } - return target; -}; - - -/***/ }), -/* 417 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * arr-flatten - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function (arr) { - return flat(arr, []); -}; -function flat(arr, res) { - var i = 0, cur; - var len = arr.length; - for (; i < len; i++) { - cur = arr[i]; - Array.isArray(cur) ? flat(cur, res) : res.push(cur); + num >>= 1; + str += str; } + + res += str; + res = res.substr(0, max); return res; } /***/ }), -/* 418 */ +/* 411 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * fill-range + * to-regex-range * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Copyright (c) 2015, 2017, Jon Schlinkert. * Released under the MIT License. */ -var util = __webpack_require__(29); -var isNumber = __webpack_require__(419); -var extend = __webpack_require__(398); -var repeat = __webpack_require__(421); -var toRegex = __webpack_require__(422); - -/** - * Return a range of numbers or letters. - * - * @param {String} `start` Start of the range - * @param {String} `stop` End of the range - * @param {String} `step` Increment or decrement to use. - * @param {Function} `fn` Custom function to modify each element in the range. - * @return {Array} - */ - -function fillRange(start, stop, step, options) { - if (typeof start === 'undefined') { - return []; - } +var repeat = __webpack_require__(410); +var isNumber = __webpack_require__(408); +var cache = {}; - if (typeof stop === 'undefined' || start === stop) { - // special case, for handling negative zero - var isString = typeof start === 'string'; - if (isNumber(start) && !toNumber(start)) { - return [isString ? '0' : 0]; - } - return [start]; +function toRegexRange(min, max, options) { + if (isNumber(min) === false) { + throw new RangeError('toRegexRange: first argument is invalid.'); } - if (typeof step !== 'number' && typeof step !== 'string') { - options = step; - step = undefined; + if (typeof max === 'undefined' || min === max) { + return String(min); } - if (typeof options === 'function') { - options = { transform: options }; - } - - var opts = extend({step: step}, options); - if (opts.step && !isValidNumber(opts.step)) { - if (opts.strictRanges === true) { - throw new TypeError('expected options.step to be a number'); - } - return []; - } - - opts.isNumber = isValidNumber(start) && isValidNumber(stop); - if (!opts.isNumber && !isValid(start, stop)) { - if (opts.strictRanges === true) { - throw new RangeError('invalid range arguments: ' + util.inspect([start, stop])); - } - return []; - } - - opts.isPadded = isPadded(start) || isPadded(stop); - opts.toString = opts.stringify - || typeof opts.step === 'string' - || typeof start === 'string' - || typeof stop === 'string' - || !opts.isNumber; - - if (opts.isPadded) { - opts.maxLength = Math.max(String(start).length, String(stop).length); - } - - // support legacy minimatch/fill-range options - if (typeof opts.optimize === 'boolean') opts.toRegex = opts.optimize; - if (typeof opts.makeRe === 'boolean') opts.toRegex = opts.makeRe; - return expand(start, stop, opts); -} - -function expand(start, stop, options) { - var a = options.isNumber ? toNumber(start) : start.charCodeAt(0); - var b = options.isNumber ? toNumber(stop) : stop.charCodeAt(0); - - var step = Math.abs(toNumber(options.step)) || 1; - if (options.toRegex && step === 1) { - return toRange(a, b, start, stop, options); - } - - var zero = {greater: [], lesser: []}; - var asc = a < b; - var arr = new Array(Math.round((asc ? b - a : a - b) / step)); - var idx = 0; - - while (asc ? a <= b : a >= b) { - var val = options.isNumber ? a : String.fromCharCode(a); - if (options.toRegex && (val >= 0 || !options.isNumber)) { - zero.greater.push(val); - } else { - zero.lesser.push(Math.abs(val)); - } - - if (options.isPadded) { - val = zeros(val, options); - } - - if (options.toString) { - val = String(val); - } - - if (typeof options.transform === 'function') { - arr[idx++] = options.transform(val, a, b, step, idx, arr, options); - } else { - arr[idx++] = val; - } - - if (asc) { - a += step; - } else { - a -= step; - } - } - - if (options.toRegex === true) { - return toSequence(arr, zero, options); - } - return arr; -} - -function toRange(a, b, start, stop, options) { - if (options.isPadded) { - return toRegex(start, stop, options); - } - - if (options.isNumber) { - return toRegex(Math.min(a, b), Math.max(a, b), options); - } - - var start = String.fromCharCode(Math.min(a, b)); - var stop = String.fromCharCode(Math.max(a, b)); - return '[' + start + '-' + stop + ']'; -} - -function toSequence(arr, zeros, options) { - var greater = '', lesser = ''; - if (zeros.greater.length) { - greater = zeros.greater.join('|'); - } - if (zeros.lesser.length) { - lesser = '-(' + zeros.lesser.join('|') + ')'; - } - var res = greater && lesser - ? greater + '|' + lesser - : greater || lesser; - - if (options.capture) { - return '(' + res + ')'; - } - return res; -} - -function zeros(val, options) { - if (options.isPadded) { - var str = String(val); - var len = str.length; - var dash = ''; - if (str.charAt(0) === '-') { - dash = '-'; - str = str.slice(1); - } - var diff = options.maxLength - len; - var pad = repeat('0', diff); - val = (dash + pad + str); - } - if (options.stringify) { - return String(val); - } - return val; -} - -function toNumber(val) { - return Number(val) || 0; -} - -function isPadded(str) { - return /^-?0\d/.test(str); -} - -function isValid(min, max) { - return (isValidNumber(min) || isValidLetter(min)) - && (isValidNumber(max) || isValidLetter(max)); -} - -function isValidLetter(ch) { - return typeof ch === 'string' && ch.length === 1 && /^\w+$/.test(ch); -} - -function isValidNumber(n) { - return isNumber(n) && !/\./.test(n); -} - -/** - * Expose `fillRange` - * @type {Function} - */ - -module.exports = fillRange; - - -/***/ }), -/* 419 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-number - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(420); - -module.exports = function isNumber(num) { - var type = typeOf(num); - - if (type === 'string') { - if (!num.trim()) return false; - } else if (type !== 'number') { - return false; - } - - return (num - num + 1) >= 0; -}; - - -/***/ }), -/* 420 */ -/***/ (function(module, exports, __webpack_require__) { - -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ - -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - var type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - - // must be a plain object - return 'object'; -}; - - -/***/ }), -/* 421 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * repeat-string - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -/** - * Results cache - */ - -var res = ''; -var cache; - -/** - * Expose `repeat` - */ - -module.exports = repeat; - -/** - * Repeat the given `string` the specified `number` - * of times. - * - * **Example:** - * - * ```js - * var repeat = require('repeat-string'); - * repeat('A', 5); - * //=> AAAAA - * ``` - * - * @param {String} `string` The string to repeat - * @param {Number} `number` The number of times to repeat the string - * @return {String} Repeated string - * @api public - */ - -function repeat(str, num) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - // cover common, quick use cases - if (num === 1) return str; - if (num === 2) return str + str; - - var max = str.length * num; - if (cache !== str || typeof cache === 'undefined') { - cache = str; - res = ''; - } else if (res.length >= max) { - return res.substr(0, max); - } - - while (max > res.length && num > 1) { - if (num & 1) { - res += str; - } - - num >>= 1; - str += str; - } - - res += str; - res = res.substr(0, max); - return res; -} - - -/***/ }), -/* 422 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * to-regex-range - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var repeat = __webpack_require__(421); -var isNumber = __webpack_require__(419); -var cache = {}; - -function toRegexRange(min, max, options) { - if (isNumber(min) === false) { - throw new RangeError('toRegexRange: first argument is invalid.'); - } - - if (typeof max === 'undefined' || min === max) { - return String(min); - } - - if (isNumber(max) === false) { - throw new RangeError('toRegexRange: second argument is invalid.'); + if (isNumber(max) === false) { + throw new RangeError('toRegexRange: second argument is invalid.'); } options = options || {}; @@ -37845,7 +36892,7 @@ module.exports = toRegexRange; /***/ }), -/* 423 */ +/* 412 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -37870,14 +36917,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 424 */ +/* 413 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(425); -var utils = __webpack_require__(410); +var Node = __webpack_require__(414); +var utils = __webpack_require__(399); /** * Braces parsers @@ -37952,7 +36999,7 @@ module.exports = function(braces, options) { .set('bracket', function() { var isInside = this.isInside('brace'); var pos = this.position(); - var m = this.match(/^(?:\[([!^]?)([^\]]{2,}|\]\-)(\]|[^*+?]+)|\[)/); + var m = this.match(/^(?:\[([!^]?)([^\]]{2,}|\]-)(\]|[^*+?]+)|\[)/); if (!m) return; var prev = this.prev(); @@ -38003,7 +37050,7 @@ module.exports = function(braces, options) { .set('multiplier', function() { var isInside = this.isInside('brace'); var pos = this.position(); - var m = this.match(/^\{(,+(?:(\{,+\})*),*|,*(?:(\{,+\})*),+)\}/); + var m = this.match(/^\{((?:,|\{,+\})+)\}/); if (!m) return; this.multiplier = true; @@ -38154,7 +37201,7 @@ module.exports = function(braces, options) { .set('text', function() { var isInside = this.isInside('brace'); var pos = this.position(); - var m = this.match(/^((?!\\)[^${}\[\]])+/); + var m = this.match(/^((?!\\)[^${}[\]])+/); if (!m) return; var prev = this.prev(); @@ -38237,15 +37284,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 425 */ +/* 414 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(415); -var define = __webpack_require__(402); -var utils = __webpack_require__(426); +var isObject = __webpack_require__(404); +var define = __webpack_require__(415); +var utils = __webpack_require__(422); var ownNames; /** @@ -38736,4486 +37783,2972 @@ exports = module.exports = Node; /***/ }), -/* 426 */ +/* 415 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - - -var typeOf = __webpack_require__(420); -var utils = module.exports; - -/** - * Returns true if the given value is a node. +/*! + * define-property * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(utils.isNode(node)); //=> true - * console.log(utils.isNode({})); //=> false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {Boolean} - * @api public + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.isNode = function(node) { - return typeOf(node) === 'object' && node.isNode === true; -}; -/** - * Emit an empty string for the given `node`. - * - * ```js - * // do nothing for beginning-of-string - * snapdragon.compiler.set('bos', utils.noop); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {undefined} - * @api public - */ -utils.noop = function(node) { - append(this, '', node); -}; +var isDescriptor = __webpack_require__(416); -/** - * Appdend `node.val` to `compiler.output`, exactly as it was created - * by the parser. - * - * ```js - * snapdragon.compiler.set('text', utils.identity); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {undefined} - * @api public - */ +module.exports = function defineProperty(obj, prop, val) { + if (typeof obj !== 'object' && typeof obj !== 'function') { + throw new TypeError('expected an object or function.'); + } -utils.identity = function(node) { - append(this, node.val, node); -}; + if (typeof prop !== 'string') { + throw new TypeError('expected `prop` to be a string.'); + } -/** - * Previously named `.emit`, this method appends the given `val` - * to `compiler.output` for the given node. Useful when you know - * what value should be appended advance, regardless of the actual - * value of `node.val`. - * - * ```js - * snapdragon.compiler - * .set('i', function(node) { - * this.mapVisit(node); - * }) - * .set('i.open', utils.append('')) - * .set('i.close', utils.append('')) - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {Function} Returns a compiler middleware function. - * @api public - */ + if (isDescriptor(val) && ('set' in val || 'get' in val)) { + return Object.defineProperty(obj, prop, val); + } -utils.append = function(val) { - return function(node) { - append(this, val, node); - }; + return Object.defineProperty(obj, prop, { + configurable: true, + enumerable: false, + writable: true, + value: val + }); }; -/** - * Used in compiler middleware, this onverts an AST node into - * an empty `text` node and deletes `node.nodes` if it exists. - * The advantage of this method is that, as opposed to completely - * removing the node, indices will not need to be re-calculated - * in sibling nodes, and nothing is appended to the output. - * - * ```js - * utils.toNoop(node); - * // convert `node.nodes` to the given value instead of deleting it - * utils.toNoop(node, []); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Array} `nodes` Optionally pass a new `nodes` value, to replace the existing `node.nodes` array. - * @api public - */ -utils.toNoop = function(node, nodes) { - if (nodes) { - node.nodes = nodes; - } else { - delete node.nodes; - node.type = 'text'; - node.val = ''; - } -}; +/***/ }), +/* 416 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Visit `node` with the given `fn`. The built-in `.visit` method in snapdragon - * automatically calls registered compilers, this allows you to pass a visitor - * function. +"use strict"; +/*! + * is-descriptor * - * ```js - * snapdragon.compiler.set('i', function(node) { - * utils.visit(node, function(childNode) { - * // do stuff with "childNode" - * return childNode; - * }); - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `fn` - * @return {Object} returns the node after recursively visiting all child nodes. - * @api public + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.visit = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(fn), 'expected a visitor function'); - fn(node); - return node.nodes ? utils.mapVisit(node, fn) : node; -}; -/** - * Map [visit](#visit) the given `fn` over `node.nodes`. This is called by - * [visit](#visit), use this method if you do not want `fn` to be called on - * the first node. - * - * ```js - * snapdragon.compiler.set('i', function(node) { - * utils.mapVisit(node, function(childNode) { - * // do stuff with "childNode" - * return childNode; - * }); - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Object} `options` - * @param {Function} `fn` - * @return {Object} returns the node - * @api public - */ -utils.mapVisit = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isArray(node.nodes), 'expected node.nodes to be an array'); - assert(isFunction(fn), 'expected a visitor function'); +var typeOf = __webpack_require__(417); +var isAccessor = __webpack_require__(418); +var isData = __webpack_require__(420); - for (var i = 0; i < node.nodes.length; i++) { - utils.visit(node.nodes[i], fn); +module.exports = function isDescriptor(obj, key) { + if (typeOf(obj) !== 'object') { + return false; } - return node; + if ('get' in obj) { + return isAccessor(obj, key); + } + return isData(obj, key); }; -/** - * Unshift an `*.open` node onto `node.nodes`. - * - * ```js - * var Node = require('snapdragon-node'); - * snapdragon.parser.set('brace', function(node) { - * var match = this.match(/^{/); - * if (match) { - * var parent = new Node({type: 'brace'}); - * utils.addOpen(parent, Node); - * console.log(parent.nodes[0]): - * // { type: 'brace.open', val: '' }; - * - * // push the parent "brace" node onto the stack - * this.push(parent); - * - * // return the parent node, so it's also added to the AST - * return brace; - * } - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the created opening node. - * @api public - */ -utils.addOpen = function(node, Node, val, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); +/***/ }), +/* 417 */ +/***/ (function(module, exports) { - if (typeof val === 'function') { - filter = val; - val = ''; - } +var toString = Object.prototype.toString; - if (typeof filter === 'function' && !filter(node)) return; - var open = new Node({ type: node.type + '.open', val: val}); - var unshift = node.unshift || node.unshiftNode; - if (typeof unshift === 'function') { - unshift.call(node, open); - } else { - utils.unshiftNode(node, open); +module.exports = function kindOf(val) { + if (val === void 0) return 'undefined'; + if (val === null) return 'null'; + + var type = typeof val; + if (type === 'boolean') return 'boolean'; + if (type === 'string') return 'string'; + if (type === 'number') return 'number'; + if (type === 'symbol') return 'symbol'; + if (type === 'function') { + return isGeneratorFn(val) ? 'generatorfunction' : 'function'; } - return open; -}; -/** - * Push a `*.close` node onto `node.nodes`. - * - * ```js - * var Node = require('snapdragon-node'); - * snapdragon.parser.set('brace', function(node) { - * var match = this.match(/^}/); - * if (match) { - * var parent = this.parent(); - * if (parent.type !== 'brace') { - * throw new Error('missing opening: ' + '}'); - * } - * - * utils.addClose(parent, Node); - * console.log(parent.nodes[parent.nodes.length - 1]): - * // { type: 'brace.close', val: '' }; - * - * // no need to return a node, since the parent - * // was already added to the AST - * return; - * } - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the created closing node. - * @api public - */ + if (isArray(val)) return 'array'; + if (isBuffer(val)) return 'buffer'; + if (isArguments(val)) return 'arguments'; + if (isDate(val)) return 'date'; + if (isError(val)) return 'error'; + if (isRegexp(val)) return 'regexp'; -utils.addClose = function(node, Node, val, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); + switch (ctorName(val)) { + case 'Symbol': return 'symbol'; + case 'Promise': return 'promise'; - if (typeof val === 'function') { - filter = val; - val = ''; - } + // Set, Map, WeakSet, WeakMap + case 'WeakMap': return 'weakmap'; + case 'WeakSet': return 'weakset'; + case 'Map': return 'map'; + case 'Set': return 'set'; - if (typeof filter === 'function' && !filter(node)) return; - var close = new Node({ type: node.type + '.close', val: val}); - var push = node.push || node.pushNode; - if (typeof push === 'function') { - push.call(node, close); - } else { - utils.pushNode(node, close); + // 8-bit typed arrays + case 'Int8Array': return 'int8array'; + case 'Uint8Array': return 'uint8array'; + case 'Uint8ClampedArray': return 'uint8clampedarray'; + + // 16-bit typed arrays + case 'Int16Array': return 'int16array'; + case 'Uint16Array': return 'uint16array'; + + // 32-bit typed arrays + case 'Int32Array': return 'int32array'; + case 'Uint32Array': return 'uint32array'; + case 'Float32Array': return 'float32array'; + case 'Float64Array': return 'float64array'; } - return close; -}; -/** - * Wraps the given `node` with `*.open` and `*.close` nodes. - * - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the node - * @api public - */ + if (isGeneratorObj(val)) { + return 'generator'; + } -utils.wrapNodes = function(node, Node, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); + // Non-plain objects + type = toString.call(val); + switch (type) { + case '[object Object]': return 'object'; + // iterators + case '[object Map Iterator]': return 'mapiterator'; + case '[object Set Iterator]': return 'setiterator'; + case '[object String Iterator]': return 'stringiterator'; + case '[object Array Iterator]': return 'arrayiterator'; + } - utils.addOpen(node, Node, filter); - utils.addClose(node, Node, filter); - return node; + // other + return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); }; -/** - * Push the given `node` onto `parent.nodes`, and set `parent` as `node.parent. - * - * ```js - * var parent = new Node({type: 'foo'}); - * var node = new Node({type: 'bar'}); - * utils.pushNode(parent, node); - * console.log(parent.nodes[0].type) // 'bar' - * console.log(node.parent.type) // 'foo' - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Object} Returns the child node - * @api public - */ +function ctorName(val) { + return val.constructor ? val.constructor.name : null; +} -utils.pushNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); +function isArray(val) { + if (Array.isArray) return Array.isArray(val); + return val instanceof Array; +} - node.define('parent', parent); - parent.nodes = parent.nodes || []; - parent.nodes.push(node); - return node; -}; +function isError(val) { + return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); +} -/** - * Unshift `node` onto `parent.nodes`, and set `parent` as `node.parent. - * - * ```js - * var parent = new Node({type: 'foo'}); - * var node = new Node({type: 'bar'}); - * utils.unshiftNode(parent, node); - * console.log(parent.nodes[0].type) // 'bar' - * console.log(node.parent.type) // 'foo' - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {undefined} - * @api public - */ +function isDate(val) { + if (val instanceof Date) return true; + return typeof val.toDateString === 'function' + && typeof val.getDate === 'function' + && typeof val.setDate === 'function'; +} -utils.unshiftNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); +function isRegexp(val) { + if (val instanceof RegExp) return true; + return typeof val.flags === 'string' + && typeof val.ignoreCase === 'boolean' + && typeof val.multiline === 'boolean' + && typeof val.global === 'boolean'; +} - node.define('parent', parent); - parent.nodes = parent.nodes || []; - parent.nodes.unshift(node); -}; +function isGeneratorFn(name, val) { + return ctorName(name) === 'GeneratorFunction'; +} -/** - * Pop the last `node` off of `parent.nodes`. The advantage of - * using this method is that it checks for `node.nodes` and works - * with any version of `snapdragon-node`. - * - * ```js - * var parent = new Node({type: 'foo'}); - * utils.pushNode(parent, new Node({type: 'foo'})); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.popNode(parent); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. - * @api public - */ +function isGeneratorObj(val) { + return typeof val.throw === 'function' + && typeof val.return === 'function' + && typeof val.next === 'function'; +} -utils.popNode = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (typeof node.pop === 'function') { - return node.pop(); +function isArguments(val) { + try { + if (typeof val.length === 'number' && typeof val.callee === 'function') { + return true; + } + } catch (err) { + if (err.message.indexOf('callee') !== -1) { + return true; + } } - return node.nodes && node.nodes.pop(); -}; + return false; +} /** - * Shift the first `node` off of `parent.nodes`. The advantage of - * using this method is that it checks for `node.nodes` and works - * with any version of `snapdragon-node`. - * - * ```js - * var parent = new Node({type: 'foo'}); - * utils.pushNode(parent, new Node({type: 'foo'})); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.shiftNode(parent); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. - * @api public + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer */ -utils.shiftNode = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (typeof node.shift === 'function') { - return node.shift(); +function isBuffer(val) { + if (val.constructor && typeof val.constructor.isBuffer === 'function') { + return val.constructor.isBuffer(val); } - return node.nodes && node.nodes.shift(); -}; + return false; +} -/** - * Remove the specified `node` from `parent.nodes`. + +/***/ }), +/* 418 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * is-accessor-descriptor * - * ```js - * var parent = new Node({type: 'abc'}); - * var foo = new Node({type: 'foo'}); - * utils.pushNode(parent, foo); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.removeNode(parent, foo); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Object|undefined} Returns the removed node, if successful, or undefined if it does not exist on `parent.nodes`. - * @api public + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.removeNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent.node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (!parent.nodes) { - return null; + +var typeOf = __webpack_require__(419); + +// accessor descriptor properties +var accessor = { + get: 'function', + set: 'function', + configurable: 'boolean', + enumerable: 'boolean' +}; + +function isAccessorDescriptor(obj, prop) { + if (typeof prop === 'string') { + var val = Object.getOwnPropertyDescriptor(obj, prop); + return typeof val !== 'undefined'; } - if (typeof parent.remove === 'function') { - return parent.remove(node); + if (typeOf(obj) !== 'object') { + return false; } - var idx = parent.nodes.indexOf(node); - if (idx !== -1) { - return parent.nodes.splice(idx, 1); + if (has(obj, 'value') || has(obj, 'writable')) { + return false; } -}; -/** - * Returns true if `node.type` matches the given `type`. Throws a - * `TypeError` if `node` is not an instance of `Node`. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(utils.isType(node, 'foo')); // false - * console.log(utils.isType(node, 'bar')); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` - * @return {Boolean} - * @api public - */ + if (!has(obj, 'get') || typeof obj.get !== 'function') { + return false; + } -utils.isType = function(node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - switch (typeOf(type)) { - case 'array': - var types = type.slice(); - for (var i = 0; i < types.length; i++) { - if (utils.isType(node, types[i])) { - return true; - } - } - return false; - case 'string': - return node.type === type; - case 'regexp': - return type.test(node.type); - default: { - throw new TypeError('expected "type" to be an array, string or regexp'); - } + // tldr: it's valid to have "set" be undefined + // "set" might be undefined if `Object.getOwnPropertyDescriptor` + // was used to get the value, and only `get` was defined by the user + if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { + return false; } -}; -/** - * Returns true if the given `node` has the given `type` in `node.nodes`. - * Throws a `TypeError` if `node` is not an instance of `Node`. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'bar'}), - * new Node({type: 'baz'}) - * ] - * }); - * console.log(utils.hasType(node, 'xyz')); // false - * console.log(utils.hasType(node, 'baz')); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` - * @return {Boolean} - * @api public - */ + for (var key in obj) { + if (!accessor.hasOwnProperty(key)) { + continue; + } -utils.hasType = function(node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (!Array.isArray(node.nodes)) return false; - for (var i = 0; i < node.nodes.length; i++) { - if (utils.isType(node.nodes[i], type)) { - return true; + if (typeOf(obj[key]) === accessor[key]) { + continue; + } + + if (typeof obj[key] !== 'undefined') { + return false; } } - return false; -}; + return true; +} + +function has(obj, key) { + return {}.hasOwnProperty.call(obj, key); +} /** - * Returns the first node from `node.nodes` of the given `type` - * - * ```js - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'text', val: 'abc'}), - * new Node({type: 'text', val: 'xyz'}) - * ] - * }); - * - * var textNode = utils.firstOfType(node.nodes, 'text'); - * console.log(textNode.val); - * //=> 'abc' - * ``` - * @param {Array} `nodes` - * @param {String} `type` - * @return {Object|undefined} Returns the first matching node or undefined. - * @api public + * Expose `isAccessorDescriptor` */ -utils.firstOfType = function(nodes, type) { - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - if (utils.isType(node, type)) { - return node; - } +module.exports = isAccessorDescriptor; + + +/***/ }), +/* 419 */ +/***/ (function(module, exports) { + +var toString = Object.prototype.toString; + +module.exports = function kindOf(val) { + if (val === void 0) return 'undefined'; + if (val === null) return 'null'; + + var type = typeof val; + if (type === 'boolean') return 'boolean'; + if (type === 'string') return 'string'; + if (type === 'number') return 'number'; + if (type === 'symbol') return 'symbol'; + if (type === 'function') { + return isGeneratorFn(val) ? 'generatorfunction' : 'function'; } -}; -/** - * Returns the node at the specified index, or the first node of the - * given `type` from `node.nodes`. - * - * ```js - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'text', val: 'abc'}), - * new Node({type: 'text', val: 'xyz'}) - * ] - * }); - * - * var nodeOne = utils.findNode(node.nodes, 'text'); - * console.log(nodeOne.val); - * //=> 'abc' - * - * var nodeTwo = utils.findNode(node.nodes, 1); - * console.log(nodeTwo.val); - * //=> 'xyz' - * ``` - * - * @param {Array} `nodes` - * @param {String|Number} `type` Node type or index. - * @return {Object} Returns a node or undefined. - * @api public - */ + if (isArray(val)) return 'array'; + if (isBuffer(val)) return 'buffer'; + if (isArguments(val)) return 'arguments'; + if (isDate(val)) return 'date'; + if (isError(val)) return 'error'; + if (isRegexp(val)) return 'regexp'; -utils.findNode = function(nodes, type) { - if (!Array.isArray(nodes)) { - return null; + switch (ctorName(val)) { + case 'Symbol': return 'symbol'; + case 'Promise': return 'promise'; + + // Set, Map, WeakSet, WeakMap + case 'WeakMap': return 'weakmap'; + case 'WeakSet': return 'weakset'; + case 'Map': return 'map'; + case 'Set': return 'set'; + + // 8-bit typed arrays + case 'Int8Array': return 'int8array'; + case 'Uint8Array': return 'uint8array'; + case 'Uint8ClampedArray': return 'uint8clampedarray'; + + // 16-bit typed arrays + case 'Int16Array': return 'int16array'; + case 'Uint16Array': return 'uint16array'; + + // 32-bit typed arrays + case 'Int32Array': return 'int32array'; + case 'Uint32Array': return 'uint32array'; + case 'Float32Array': return 'float32array'; + case 'Float64Array': return 'float64array'; } - if (typeof type === 'number') { - return nodes[type]; + + if (isGeneratorObj(val)) { + return 'generator'; } - return utils.firstOfType(nodes, type); -}; -/** - * Returns true if the given node is an "*.open" node. - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * - * console.log(utils.isOpen(brace)); // false - * console.log(utils.isOpen(open)); // true - * console.log(utils.isOpen(close)); // false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ + // Non-plain objects + type = toString.call(val); + switch (type) { + case '[object Object]': return 'object'; + // iterators + case '[object Map Iterator]': return 'mapiterator'; + case '[object Set Iterator]': return 'setiterator'; + case '[object String Iterator]': return 'stringiterator'; + case '[object Array Iterator]': return 'arrayiterator'; + } -utils.isOpen = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - return node.type.slice(-5) === '.open'; + // other + return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); }; -/** - * Returns true if the given node is a "*.close" node. - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * - * console.log(utils.isClose(brace)); // false - * console.log(utils.isClose(open)); // false - * console.log(utils.isClose(close)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ +function ctorName(val) { + return val.constructor ? val.constructor.name : null; +} -utils.isClose = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - return node.type.slice(-6) === '.close'; -}; +function isArray(val) { + if (Array.isArray) return Array.isArray(val); + return val instanceof Array; +} -/** - * Returns true if `node.nodes` **has** an `.open` node - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var open = new Node({type: 'brace.open'}); - * console.log(utils.hasOpen(brace)); // false - * - * brace.pushNode(open); - * console.log(utils.hasOpen(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ +function isError(val) { + return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); +} -utils.hasOpen = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - var first = node.first || node.nodes ? node.nodes[0] : null; - if (utils.isNode(first)) { - return first.type === node.type + '.open'; +function isDate(val) { + if (val instanceof Date) return true; + return typeof val.toDateString === 'function' + && typeof val.getDate === 'function' + && typeof val.setDate === 'function'; +} + +function isRegexp(val) { + if (val instanceof RegExp) return true; + return typeof val.flags === 'string' + && typeof val.ignoreCase === 'boolean' + && typeof val.multiline === 'boolean' + && typeof val.global === 'boolean'; +} + +function isGeneratorFn(name, val) { + return ctorName(name) === 'GeneratorFunction'; +} + +function isGeneratorObj(val) { + return typeof val.throw === 'function' + && typeof val.return === 'function' + && typeof val.next === 'function'; +} + +function isArguments(val) { + try { + if (typeof val.length === 'number' && typeof val.callee === 'function') { + return true; + } + } catch (err) { + if (err.message.indexOf('callee') !== -1) { + return true; + } } return false; -}; +} /** - * Returns true if `node.nodes` **has** a `.close` node - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var close = new Node({type: 'brace.close'}); - * console.log(utils.hasClose(brace)); // false - * - * brace.pushNode(close); - * console.log(utils.hasClose(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer */ -utils.hasClose = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - var last = node.last || node.nodes ? node.nodes[node.nodes.length - 1] : null; - if (utils.isNode(last)) { - return last.type === node.type + '.close'; +function isBuffer(val) { + if (val.constructor && typeof val.constructor.isBuffer === 'function') { + return val.constructor.isBuffer(val); } return false; -}; +} -/** - * Returns true if `node.nodes` has both `.open` and `.close` nodes - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * console.log(utils.hasOpen(brace)); // false - * console.log(utils.hasClose(brace)); // false - * - * brace.pushNode(open); - * brace.pushNode(close); - * console.log(utils.hasOpen(brace)); // true - * console.log(utils.hasClose(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ -utils.hasOpenAndClose = function(node) { - return utils.hasOpen(node) && utils.hasClose(node); -}; +/***/ }), +/* 420 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Push the given `node` onto the `state.inside` array for the - * given type. This array is used as a specialized "stack" for - * only the given `node.type`. +"use strict"; +/*! + * is-data-descriptor * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * utils.addType(state, node); - * console.log(state.inside); - * //=> { brace: [{type: 'brace'}] } - * ``` - * @param {Object} `state` The `compiler.state` object or custom state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Array} Returns the `state.inside` stack for the given type. - * @api public + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.addType = function(state, node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - var type = node.parent - ? node.parent.type - : node.type.replace(/\.open$/, ''); - if (!state.hasOwnProperty('inside')) { - state.inside = {}; +var typeOf = __webpack_require__(421); + +module.exports = function isDataDescriptor(obj, prop) { + // data descriptor properties + var data = { + configurable: 'boolean', + enumerable: 'boolean', + writable: 'boolean' + }; + + if (typeOf(obj) !== 'object') { + return false; } - if (!state.inside.hasOwnProperty(type)) { - state.inside[type] = []; + + if (typeof prop === 'string') { + var val = Object.getOwnPropertyDescriptor(obj, prop); + return typeof val !== 'undefined'; } - var arr = state.inside[type]; - arr.push(node); - return arr; -}; + if (!('value' in obj) && !('writable' in obj)) { + return false; + } -/** - * Remove the given `node` from the `state.inside` array for the - * given type. This array is used as a specialized "stack" for - * only the given `node.type`. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * utils.addType(state, node); - * console.log(state.inside); - * //=> { brace: [{type: 'brace'}] } - * utils.removeType(state, node); - * //=> { brace: [] } - * ``` - * @param {Object} `state` The `compiler.state` object or custom state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Array} Returns the `state.inside` stack for the given type. - * @api public - */ + for (var key in obj) { + if (key === 'value') continue; -utils.removeType = function(state, node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); + if (!data.hasOwnProperty(key)) { + continue; + } - var type = node.parent - ? node.parent.type - : node.type.replace(/\.close$/, ''); + if (typeOf(obj[key]) === data[key]) { + continue; + } - if (state.inside.hasOwnProperty(type)) { - return state.inside[type].pop(); + if (typeof obj[key] !== 'undefined') { + return false; + } } + return true; }; -/** - * Returns true if `node.val` is an empty string, or `node.nodes` does - * not contain any non-empty text nodes. - * - * ```js - * var node = new Node({type: 'text'}); - * utils.isEmpty(node); //=> true - * node.val = 'foo'; - * utils.isEmpty(node); //=> false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `fn` - * @return {Boolean} - * @api public - */ - -utils.isEmpty = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - if (!Array.isArray(node.nodes)) { - if (node.type !== 'text') { - return true; - } - if (typeof fn === 'function') { - return fn(node, node.parent); - } - return !utils.trim(node.val); - } - for (var i = 0; i < node.nodes.length; i++) { - var child = node.nodes[i]; - if (utils.isOpen(child) || utils.isClose(child)) { - continue; - } - if (!utils.isEmpty(child, fn)) { - return false; - } - } - - return true; -}; +/***/ }), +/* 421 */ +/***/ (function(module, exports) { -/** - * Returns true if the `state.inside` stack for the given type exists - * and has one or more nodes on it. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * console.log(utils.isInsideType(state, 'brace')); //=> false - * utils.addType(state, node); - * console.log(utils.isInsideType(state, 'brace')); //=> true - * utils.removeType(state, node); - * console.log(utils.isInsideType(state, 'brace')); //=> false - * ``` - * @param {Object} `state` - * @param {String} `type` - * @return {Boolean} - * @api public - */ +var toString = Object.prototype.toString; -utils.isInsideType = function(state, type) { - assert(isObject(state), 'expected state to be an object'); - assert(isString(type), 'expected type to be a string'); +module.exports = function kindOf(val) { + if (val === void 0) return 'undefined'; + if (val === null) return 'null'; - if (!state.hasOwnProperty('inside')) { - return false; + var type = typeof val; + if (type === 'boolean') return 'boolean'; + if (type === 'string') return 'string'; + if (type === 'number') return 'number'; + if (type === 'symbol') return 'symbol'; + if (type === 'function') { + return isGeneratorFn(val) ? 'generatorfunction' : 'function'; } - if (!state.inside.hasOwnProperty(type)) { - return false; - } + if (isArray(val)) return 'array'; + if (isBuffer(val)) return 'buffer'; + if (isArguments(val)) return 'arguments'; + if (isDate(val)) return 'date'; + if (isError(val)) return 'error'; + if (isRegexp(val)) return 'regexp'; - return state.inside[type].length > 0; -}; + switch (ctorName(val)) { + case 'Symbol': return 'symbol'; + case 'Promise': return 'promise'; -/** - * Returns true if `node` is either a child or grand-child of the given `type`, - * or `state.inside[type]` is a non-empty array. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * console.log(utils.isInside(state, open, 'brace')); //=> false - * utils.pushNode(node, open); - * console.log(utils.isInside(state, open, 'brace')); //=> true - * ``` - * @param {Object} `state` Either the `compiler.state` object, if it exists, or a user-supplied state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` The `node.type` to check for. - * @return {Boolean} - * @api public - */ + // Set, Map, WeakSet, WeakMap + case 'WeakMap': return 'weakmap'; + case 'WeakSet': return 'weakset'; + case 'Map': return 'map'; + case 'Set': return 'set'; -utils.isInside = function(state, node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); + // 8-bit typed arrays + case 'Int8Array': return 'int8array'; + case 'Uint8Array': return 'uint8array'; + case 'Uint8ClampedArray': return 'uint8clampedarray'; - if (Array.isArray(type)) { - for (var i = 0; i < type.length; i++) { - if (utils.isInside(state, node, type[i])) { - return true; - } - } - return false; - } + // 16-bit typed arrays + case 'Int16Array': return 'int16array'; + case 'Uint16Array': return 'uint16array'; - var parent = node.parent; - if (typeof type === 'string') { - return (parent && parent.type === type) || utils.isInsideType(state, type); + // 32-bit typed arrays + case 'Int32Array': return 'int32array'; + case 'Uint32Array': return 'uint32array'; + case 'Float32Array': return 'float32array'; + case 'Float64Array': return 'float64array'; } - if (typeOf(type) === 'regexp') { - if (parent && parent.type && type.test(parent.type)) { - return true; - } - - var keys = Object.keys(state.inside); - var len = keys.length; - var idx = -1; - while (++idx < len) { - var key = keys[idx]; - var val = state.inside[key]; - - if (Array.isArray(val) && val.length !== 0 && type.test(key)) { - return true; - } - } + if (isGeneratorObj(val)) { + return 'generator'; } - return false; -}; - -/** - * Get the last `n` element from the given `array`. Used for getting - * a node from `node.nodes.` - * - * @param {Array} `array` - * @param {Number} `n` - * @return {undefined} - * @api public - */ - -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - -/** - * Cast the given `val` to an array. - * - * ```js - * console.log(utils.arrayify('')); - * //=> [] - * console.log(utils.arrayify('foo')); - * //=> ['foo'] - * console.log(utils.arrayify(['foo'])); - * //=> ['foo'] - * ``` - * @param {any} `val` - * @return {Array} - * @api public - */ -utils.arrayify = function(val) { - if (typeof val === 'string' && val !== '') { - return [val]; - } - if (!Array.isArray(val)) { - return []; + // Non-plain objects + type = toString.call(val); + switch (type) { + case '[object Object]': return 'object'; + // iterators + case '[object Map Iterator]': return 'mapiterator'; + case '[object Set Iterator]': return 'setiterator'; + case '[object String Iterator]': return 'stringiterator'; + case '[object Array Iterator]': return 'arrayiterator'; } - return val; -}; - -/** - * Convert the given `val` to a string by joining with `,`. Useful - * for creating a cheerio/CSS/DOM-style selector from a list of strings. - * - * @param {any} `val` - * @return {Array} - * @api public - */ - -utils.stringify = function(val) { - return utils.arrayify(val).join(','); -}; -/** - * Ensure that the given value is a string and call `.trim()` on it, - * or return an empty string. - * - * @param {String} `str` - * @return {String} - * @api public - */ - -utils.trim = function(str) { - return typeof str === 'string' ? str.trim() : ''; + // other + return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); }; -/** - * Return true if val is an object - */ - -function isObject(val) { - return typeOf(val) === 'object'; +function ctorName(val) { + return val.constructor ? val.constructor.name : null; } -/** - * Return true if val is a string - */ - -function isString(val) { - return typeof val === 'string'; +function isArray(val) { + if (Array.isArray) return Array.isArray(val); + return val instanceof Array; } -/** - * Return true if val is a function - */ +function isError(val) { + return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); +} -function isFunction(val) { - return typeof val === 'function'; +function isDate(val) { + if (val instanceof Date) return true; + return typeof val.toDateString === 'function' + && typeof val.getDate === 'function' + && typeof val.setDate === 'function'; } -/** - * Return true if val is an array - */ +function isRegexp(val) { + if (val instanceof RegExp) return true; + return typeof val.flags === 'string' + && typeof val.ignoreCase === 'boolean' + && typeof val.multiline === 'boolean' + && typeof val.global === 'boolean'; +} -function isArray(val) { - return Array.isArray(val); +function isGeneratorFn(name, val) { + return ctorName(name) === 'GeneratorFunction'; } -/** - * Shim to ensure the `.append` methods work with any version of snapdragon - */ +function isGeneratorObj(val) { + return typeof val.throw === 'function' + && typeof val.return === 'function' + && typeof val.next === 'function'; +} -function append(compiler, val, node) { - if (typeof compiler.append !== 'function') { - return compiler.emit(val, node); +function isArguments(val) { + try { + if (typeof val.length === 'number' && typeof val.callee === 'function') { + return true; + } + } catch (err) { + if (err.message.indexOf('callee') !== -1) { + return true; + } } - return compiler.append(val, node); + return false; } /** - * Simplified assertion. Throws an error is `val` is falsey. + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer */ -function assert(val, message) { - if (!val) throw new Error(message); +function isBuffer(val) { + if (val.constructor && typeof val.constructor.isBuffer === 'function') { + return val.constructor.isBuffer(val); + } + return false; } /***/ }), -/* 427 */ +/* 422 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Snapdragon = __webpack_require__(428); -var compilers = __webpack_require__(409); -var parsers = __webpack_require__(424); -var utils = __webpack_require__(410); +var typeOf = __webpack_require__(409); +var utils = module.exports; /** - * Customize Snapdragon parser and renderer + * Returns true if the given value is a node. + * + * ```js + * var Node = require('snapdragon-node'); + * var node = new Node({type: 'foo'}); + * console.log(utils.isNode(node)); //=> true + * console.log(utils.isNode({})); //=> false + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @returns {Boolean} + * @api public */ -function Braces(options) { - this.options = utils.extend({}, options); -} +utils.isNode = function(node) { + return typeOf(node) === 'object' && node.isNode === true; +}; /** - * Initialize braces + * Emit an empty string for the given `node`. + * + * ```js + * // do nothing for beginning-of-string + * snapdragon.compiler.set('bos', utils.noop); + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @returns {undefined} + * @api public */ -Braces.prototype.init = function(options) { - var opts = utils.createOptions({}, this.options, options); - this.snapdragon = this.options.snapdragon || new Snapdragon(opts); - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; - - compilers(this.snapdragon, opts); - parsers(this.snapdragon, opts); - - /** - * Call Snapdragon `.parse` method. When AST is returned, we check to - * see if any unclosed braces are left on the stack and, if so, we iterate - * over the stack and correct the AST so that compilers are called in the correct - * order and unbalance braces are properly escaped. - */ - - utils.define(this.snapdragon, 'parse', function(pattern, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - this.parser.ast.input = pattern; - - var stack = this.parser.stack; - while (stack.length) { - addParent({type: 'brace.close', val: ''}, stack.pop()); - } - - function addParent(node, parent) { - utils.define(node, 'parent', parent); - parent.nodes.push(node); - } - - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); +utils.noop = function(node) { + append(this, '', node); }; /** - * Lazily initialize braces + * Appdend `node.val` to `compiler.output`, exactly as it was created + * by the parser. + * + * ```js + * snapdragon.compiler.set('text', utils.identity); + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @returns {undefined} + * @api public */ -Braces.prototype.lazyInit = function(options) { - if (!this.isInitialized) { - this.isInitialized = true; - this.init(options); - } +utils.identity = function(node) { + append(this, node.val, node); }; /** - * Decorate `.parse` method + * Previously named `.emit`, this method appends the given `val` + * to `compiler.output` for the given node. Useful when you know + * what value should be appended advance, regardless of the actual + * value of `node.val`. + * + * ```js + * snapdragon.compiler + * .set('i', function(node) { + * this.mapVisit(node); + * }) + * .set('i.open', utils.append('')) + * .set('i.close', utils.append('')) + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @returns {Function} Returns a compiler middleware function. + * @api public */ -Braces.prototype.parse = function(ast, options) { - if (utils.isObject(ast) && ast.nodes) return ast; - this.lazyInit(options); - return this.snapdragon.parse(ast, options); +utils.append = function(val) { + return function(node) { + append(this, val, node); + }; }; /** - * Decorate `.compile` method + * Used in compiler middleware, this onverts an AST node into + * an empty `text` node and deletes `node.nodes` if it exists. + * The advantage of this method is that, as opposed to completely + * removing the node, indices will not need to be re-calculated + * in sibling nodes, and nothing is appended to the output. + * + * ```js + * utils.toNoop(node); + * // convert `node.nodes` to the given value instead of deleting it + * utils.toNoop(node, []); + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Array} `nodes` Optionally pass a new `nodes` value, to replace the existing `node.nodes` array. + * @api public */ -Braces.prototype.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = this.parse(ast, options); +utils.toNoop = function(node, nodes) { + if (nodes) { + node.nodes = nodes; } else { - this.lazyInit(options); + delete node.nodes; + node.type = 'text'; + node.val = ''; } - var res = this.snapdragon.compile(ast, options); - return res; -}; - -/** - * Expand - */ - -Braces.prototype.expand = function(pattern) { - var ast = this.parse(pattern, {expand: true}); - return this.compile(ast, {expand: true}); }; /** - * Optimize + * Visit `node` with the given `fn`. The built-in `.visit` method in snapdragon + * automatically calls registered compilers, this allows you to pass a visitor + * function. + * + * ```js + * snapdragon.compiler.set('i', function(node) { + * utils.visit(node, function(childNode) { + * // do stuff with "childNode" + * return childNode; + * }); + * }); + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `fn` + * @return {Object} returns the node after recursively visiting all child nodes. + * @api public */ -Braces.prototype.optimize = function(pattern) { - var ast = this.parse(pattern, {optimize: true}); - return this.compile(ast, {optimize: true}); +utils.visit = function(node, fn) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isFunction(fn), 'expected a visitor function'); + fn(node); + return node.nodes ? utils.mapVisit(node, fn) : node; }; /** - * Expose `Braces` - */ - -module.exports = Braces; - - -/***/ }), -/* 428 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Base = __webpack_require__(429); -var define = __webpack_require__(477); -var Compiler = __webpack_require__(484); -var Parser = __webpack_require__(521); -var utils = __webpack_require__(501); -var regexCache = {}; -var cache = {}; - -/** - * Create a new instance of `Snapdragon` with the given `options`. + * Map [visit](#visit) the given `fn` over `node.nodes`. This is called by + * [visit](#visit), use this method if you do not want `fn` to be called on + * the first node. * * ```js - * var snapdragon = new Snapdragon(); + * snapdragon.compiler.set('i', function(node) { + * utils.mapVisit(node, function(childNode) { + * // do stuff with "childNode" + * return childNode; + * }); + * }); * ``` - * + * @param {Object} `node` Instance of [snapdragon-node][] * @param {Object} `options` + * @param {Function} `fn` + * @return {Object} returns the node * @api public */ -function Snapdragon(options) { - Base.call(this, null, options); - this.options = utils.extend({source: 'string'}, this.options); - this.compiler = new Compiler(this.options); - this.parser = new Parser(this.options); +utils.mapVisit = function(node, fn) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isArray(node.nodes), 'expected node.nodes to be an array'); + assert(isFunction(fn), 'expected a visitor function'); - Object.defineProperty(this, 'compilers', { - get: function() { - return this.compiler.compilers; - } - }); - - Object.defineProperty(this, 'parsers', { - get: function() { - return this.parser.parsers; - } - }); - - Object.defineProperty(this, 'regex', { - get: function() { - return this.parser.regex; - } - }); -} + for (var i = 0; i < node.nodes.length; i++) { + utils.visit(node.nodes[i], fn); + } + return node; +}; /** - * Inherit Base + * Unshift an `*.open` node onto `node.nodes`. + * + * ```js + * var Node = require('snapdragon-node'); + * snapdragon.parser.set('brace', function(node) { + * var match = this.match(/^{/); + * if (match) { + * var parent = new Node({type: 'brace'}); + * utils.addOpen(parent, Node); + * console.log(parent.nodes[0]): + * // { type: 'brace.open', val: '' }; + * + * // push the parent "brace" node onto the stack + * this.push(parent); + * + * // return the parent node, so it's also added to the AST + * return brace; + * } + * }); + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. + * @param {Function} `filter` Optionaly specify a filter function to exclude the node. + * @return {Object} Returns the created opening node. + * @api public */ -Base.extend(Snapdragon); +utils.addOpen = function(node, Node, val, filter) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isFunction(Node), 'expected Node to be a constructor function'); + + if (typeof val === 'function') { + filter = val; + val = ''; + } + + if (typeof filter === 'function' && !filter(node)) return; + var open = new Node({ type: node.type + '.open', val: val}); + var unshift = node.unshift || node.unshiftNode; + if (typeof unshift === 'function') { + unshift.call(node, open); + } else { + utils.unshiftNode(node, open); + } + return open; +}; /** - * Add a parser to `snapdragon.parsers` for capturing the given `type` using - * the specified regex or parser function. A function is useful if you need - * to customize how the token is created and/or have access to the parser - * instance to check options, etc. + * Push a `*.close` node onto `node.nodes`. * * ```js - * snapdragon - * .capture('slash', /^\//) - * .capture('dot', function() { - * var pos = this.position(); - * var m = this.match(/^\./); - * if (!m) return; - * return pos({ - * type: 'dot', - * val: m[0] - * }); - * }); + * var Node = require('snapdragon-node'); + * snapdragon.parser.set('brace', function(node) { + * var match = this.match(/^}/); + * if (match) { + * var parent = this.parent(); + * if (parent.type !== 'brace') { + * throw new Error('missing opening: ' + '}'); + * } + * + * utils.addClose(parent, Node); + * console.log(parent.nodes[parent.nodes.length - 1]): + * // { type: 'brace.close', val: '' }; + * + * // no need to return a node, since the parent + * // was already added to the AST + * return; + * } + * }); * ``` - * @param {String} `type` - * @param {RegExp|Function} `regex` - * @return {Object} Returns the parser instance for chaining + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. + * @param {Function} `filter` Optionaly specify a filter function to exclude the node. + * @return {Object} Returns the created closing node. * @api public */ -Snapdragon.prototype.capture = function() { - return this.parser.capture.apply(this.parser, arguments); +utils.addClose = function(node, Node, val, filter) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isFunction(Node), 'expected Node to be a constructor function'); + + if (typeof val === 'function') { + filter = val; + val = ''; + } + + if (typeof filter === 'function' && !filter(node)) return; + var close = new Node({ type: node.type + '.close', val: val}); + var push = node.push || node.pushNode; + if (typeof push === 'function') { + push.call(node, close); + } else { + utils.pushNode(node, close); + } + return close; }; /** - * Register a plugin `fn`. + * Wraps the given `node` with `*.open` and `*.close` nodes. * - * ```js - * var snapdragon = new Snapdgragon([options]); - * snapdragon.use(function() { - * console.log(this); //<= snapdragon instance - * console.log(this.parser); //<= parser instance - * console.log(this.compiler); //<= compiler instance - * }); - * ``` - * @param {Object} `fn` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. + * @param {Function} `filter` Optionaly specify a filter function to exclude the node. + * @return {Object} Returns the node * @api public */ -Snapdragon.prototype.use = function(fn) { - fn.call(this, this); - return this; +utils.wrapNodes = function(node, Node, filter) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isFunction(Node), 'expected Node to be a constructor function'); + + utils.addOpen(node, Node, filter); + utils.addClose(node, Node, filter); + return node; }; /** - * Parse the given `str`. + * Push the given `node` onto `parent.nodes`, and set `parent` as `node.parent. * * ```js - * var snapdragon = new Snapdgragon([options]); - * // register parsers - * snapdragon.parser.use(function() {}); - * - * // parse - * var ast = snapdragon.parse('foo/bar'); - * console.log(ast); + * var parent = new Node({type: 'foo'}); + * var node = new Node({type: 'bar'}); + * utils.pushNode(parent, node); + * console.log(parent.nodes[0].type) // 'bar' + * console.log(node.parent.type) // 'foo' * ``` - * @param {String} `str` - * @param {Object} `options` Set `options.sourcemap` to true to enable source maps. - * @return {Object} Returns an AST. + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Object} Returns the child node * @api public */ -Snapdragon.prototype.parse = function(str, options) { - this.options = utils.extend({}, this.options, options); - var parsed = this.parser.parse(str, this.options); +utils.pushNode = function(parent, node) { + assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); + assert(utils.isNode(node), 'expected node to be an instance of Node'); - // add non-enumerable parser reference - define(parsed, 'parser', this.parser); - return parsed; + node.define('parent', parent); + parent.nodes = parent.nodes || []; + parent.nodes.push(node); + return node; }; /** - * Compile the given `AST`. + * Unshift `node` onto `parent.nodes`, and set `parent` as `node.parent. * * ```js - * var snapdragon = new Snapdgragon([options]); - * // register plugins - * snapdragon.use(function() {}); - * // register parser plugins - * snapdragon.parser.use(function() {}); - * // register compiler plugins - * snapdragon.compiler.use(function() {}); - * - * // parse - * var ast = snapdragon.parse('foo/bar'); - * - * // compile - * var res = snapdragon.compile(ast); - * console.log(res.output); + * var parent = new Node({type: 'foo'}); + * var node = new Node({type: 'bar'}); + * utils.unshiftNode(parent, node); + * console.log(parent.nodes[0].type) // 'bar' + * console.log(node.parent.type) // 'foo' * ``` - * @param {Object} `ast` - * @param {Object} `options` - * @return {Object} Returns an object with an `output` property with the rendered string. + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {undefined} * @api public */ -Snapdragon.prototype.compile = function(ast, options) { - this.options = utils.extend({}, this.options, options); - var compiled = this.compiler.compile(ast, this.options); +utils.unshiftNode = function(parent, node) { + assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); + assert(utils.isNode(node), 'expected node to be an instance of Node'); - // add non-enumerable compiler reference - define(compiled, 'compiler', this.compiler); - return compiled; + node.define('parent', parent); + parent.nodes = parent.nodes || []; + parent.nodes.unshift(node); }; /** - * Expose `Snapdragon` + * Pop the last `node` off of `parent.nodes`. The advantage of + * using this method is that it checks for `node.nodes` and works + * with any version of `snapdragon-node`. + * + * ```js + * var parent = new Node({type: 'foo'}); + * utils.pushNode(parent, new Node({type: 'foo'})); + * utils.pushNode(parent, new Node({type: 'bar'})); + * utils.pushNode(parent, new Node({type: 'baz'})); + * console.log(parent.nodes.length); //=> 3 + * utils.popNode(parent); + * console.log(parent.nodes.length); //=> 2 + * ``` + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. + * @api public */ -module.exports = Snapdragon; +utils.popNode = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + if (typeof node.pop === 'function') { + return node.pop(); + } + return node.nodes && node.nodes.pop(); +}; /** - * Expose `Parser` and `Compiler` + * Shift the first `node` off of `parent.nodes`. The advantage of + * using this method is that it checks for `node.nodes` and works + * with any version of `snapdragon-node`. + * + * ```js + * var parent = new Node({type: 'foo'}); + * utils.pushNode(parent, new Node({type: 'foo'})); + * utils.pushNode(parent, new Node({type: 'bar'})); + * utils.pushNode(parent, new Node({type: 'baz'})); + * console.log(parent.nodes.length); //=> 3 + * utils.shiftNode(parent); + * console.log(parent.nodes.length); //=> 2 + * ``` + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. + * @api public */ -module.exports.Compiler = Compiler; -module.exports.Parser = Parser; +utils.shiftNode = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + if (typeof node.shift === 'function') { + return node.shift(); + } + return node.nodes && node.nodes.shift(); +}; +/** + * Remove the specified `node` from `parent.nodes`. + * + * ```js + * var parent = new Node({type: 'abc'}); + * var foo = new Node({type: 'foo'}); + * utils.pushNode(parent, foo); + * utils.pushNode(parent, new Node({type: 'bar'})); + * utils.pushNode(parent, new Node({type: 'baz'})); + * console.log(parent.nodes.length); //=> 3 + * utils.removeNode(parent, foo); + * console.log(parent.nodes.length); //=> 2 + * ``` + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Object|undefined} Returns the removed node, if successful, or undefined if it does not exist on `parent.nodes`. + * @api public + */ -/***/ }), -/* 429 */ -/***/ (function(module, exports, __webpack_require__) { +utils.removeNode = function(parent, node) { + assert(utils.isNode(parent), 'expected parent.node to be an instance of Node'); + assert(utils.isNode(node), 'expected node to be an instance of Node'); -"use strict"; + if (!parent.nodes) { + return null; + } + if (typeof parent.remove === 'function') { + return parent.remove(node); + } -var util = __webpack_require__(29); -var define = __webpack_require__(402); -var CacheBase = __webpack_require__(430); -var Emitter = __webpack_require__(431); -var isObject = __webpack_require__(415); -var merge = __webpack_require__(449); -var pascal = __webpack_require__(452); -var cu = __webpack_require__(453); + var idx = parent.nodes.indexOf(node); + if (idx !== -1) { + return parent.nodes.splice(idx, 1); + } +}; /** - * Optionally define a custom `cache` namespace to use. + * Returns true if `node.type` matches the given `type`. Throws a + * `TypeError` if `node` is not an instance of `Node`. + * + * ```js + * var Node = require('snapdragon-node'); + * var node = new Node({type: 'foo'}); + * console.log(utils.isType(node, 'foo')); // false + * console.log(utils.isType(node, 'bar')); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {String} `type` + * @return {Boolean} + * @api public */ -function namespace(name) { - var Cache = name ? CacheBase.namespace(name) : CacheBase; - var fns = []; +utils.isType = function(node, type) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + switch (typeOf(type)) { + case 'array': + var types = type.slice(); + for (var i = 0; i < types.length; i++) { + if (utils.isType(node, types[i])) { + return true; + } + } + return false; + case 'string': + return node.type === type; + case 'regexp': + return type.test(node.type); + default: { + throw new TypeError('expected "type" to be an array, string or regexp'); + } + } +}; - /** - * Create an instance of `Base` with the given `config` and `options`. - * - * ```js - * // initialize with `config` and `options` - * var app = new Base({isApp: true}, {abc: true}); - * app.set('foo', 'bar'); - * - * // values defined with the given `config` object will be on the root of the instance - * console.log(app.baz); //=> undefined - * console.log(app.foo); //=> 'bar' - * // or use `.get` - * console.log(app.get('isApp')); //=> true - * console.log(app.get('foo')); //=> 'bar' - * - * // values defined with the given `options` object will be on `app.options - * console.log(app.options.abc); //=> true - * ``` - * - * @param {Object} `config` If supplied, this object is passed to [cache-base][] to merge onto the the instance upon instantiation. - * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object. - * @api public - */ +/** + * Returns true if the given `node` has the given `type` in `node.nodes`. + * Throws a `TypeError` if `node` is not an instance of `Node`. + * + * ```js + * var Node = require('snapdragon-node'); + * var node = new Node({ + * type: 'foo', + * nodes: [ + * new Node({type: 'bar'}), + * new Node({type: 'baz'}) + * ] + * }); + * console.log(utils.hasType(node, 'xyz')); // false + * console.log(utils.hasType(node, 'baz')); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {String} `type` + * @return {Boolean} + * @api public + */ - function Base(config, options) { - if (!(this instanceof Base)) { - return new Base(config, options); +utils.hasType = function(node, type) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + if (!Array.isArray(node.nodes)) return false; + for (var i = 0; i < node.nodes.length; i++) { + if (utils.isType(node.nodes[i], type)) { + return true; } - Cache.call(this, config); - this.is('base'); - this.initBase(config, options); } + return false; +}; - /** - * Inherit cache-base - */ - - util.inherits(Base, Cache); +/** + * Returns the first node from `node.nodes` of the given `type` + * + * ```js + * var node = new Node({ + * type: 'foo', + * nodes: [ + * new Node({type: 'text', val: 'abc'}), + * new Node({type: 'text', val: 'xyz'}) + * ] + * }); + * + * var textNode = utils.firstOfType(node.nodes, 'text'); + * console.log(textNode.val); + * //=> 'abc' + * ``` + * @param {Array} `nodes` + * @param {String} `type` + * @return {Object|undefined} Returns the first matching node or undefined. + * @api public + */ - /** - * Add static emitter methods - */ +utils.firstOfType = function(nodes, type) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (utils.isType(node, type)) { + return node; + } + } +}; - Emitter(Base); +/** + * Returns the node at the specified index, or the first node of the + * given `type` from `node.nodes`. + * + * ```js + * var node = new Node({ + * type: 'foo', + * nodes: [ + * new Node({type: 'text', val: 'abc'}), + * new Node({type: 'text', val: 'xyz'}) + * ] + * }); + * + * var nodeOne = utils.findNode(node.nodes, 'text'); + * console.log(nodeOne.val); + * //=> 'abc' + * + * var nodeTwo = utils.findNode(node.nodes, 1); + * console.log(nodeTwo.val); + * //=> 'xyz' + * ``` + * + * @param {Array} `nodes` + * @param {String|Number} `type` Node type or index. + * @return {Object} Returns a node or undefined. + * @api public + */ - /** - * Initialize `Base` defaults with the given `config` object - */ +utils.findNode = function(nodes, type) { + if (!Array.isArray(nodes)) { + return null; + } + if (typeof type === 'number') { + return nodes[type]; + } + return utils.firstOfType(nodes, type); +}; - Base.prototype.initBase = function(config, options) { - this.options = merge({}, this.options, options); - this.cache = this.cache || {}; - this.define('registered', {}); - if (name) this[name] = {}; +/** + * Returns true if the given node is an "*.open" node. + * + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({type: 'brace'}); + * var open = new Node({type: 'brace.open'}); + * var close = new Node({type: 'brace.close'}); + * + * console.log(utils.isOpen(brace)); // false + * console.log(utils.isOpen(open)); // true + * console.log(utils.isOpen(close)); // false + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public + */ - // make `app._callbacks` non-enumerable - this.define('_callbacks', this._callbacks); - if (isObject(config)) { - this.visit('set', config); - } - Base.run(this, 'use', fns); - }; +utils.isOpen = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + return node.type.slice(-5) === '.open'; +}; - /** - * Set the given `name` on `app._name` and `app.is*` properties. Used for doing - * lookups in plugins. - * - * ```js - * app.is('foo'); - * console.log(app._name); - * //=> 'foo' - * console.log(app.isFoo); - * //=> true - * app.is('bar'); - * console.log(app.isFoo); - * //=> true - * console.log(app.isBar); - * //=> true - * console.log(app._name); - * //=> 'bar' - * ``` - * @name .is - * @param {String} `name` - * @return {Boolean} - * @api public - */ - - Base.prototype.is = function(name) { - if (typeof name !== 'string') { - throw new TypeError('expected name to be a string'); - } - this.define('is' + pascal(name), true); - this.define('_name', name); - this.define('_appname', name); - return this; - }; - - /** - * Returns true if a plugin has already been registered on an instance. - * - * Plugin implementors are encouraged to use this first thing in a plugin - * to prevent the plugin from being called more than once on the same - * instance. - * - * ```js - * var base = new Base(); - * base.use(function(app) { - * if (app.isRegistered('myPlugin')) return; - * // do stuff to `app` - * }); - * - * // to also record the plugin as being registered - * base.use(function(app) { - * if (app.isRegistered('myPlugin', true)) return; - * // do stuff to `app` - * }); - * ``` - * @name .isRegistered - * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once. - * @param {String} `name` The plugin name. - * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument. - * @return {Boolean} Returns true if a plugin is already registered. - * @api public - */ - - Base.prototype.isRegistered = function(name, register) { - if (this.registered.hasOwnProperty(name)) { - return true; - } - if (register !== false) { - this.registered[name] = true; - this.emit('plugin', name); - } - return false; - }; - - /** - * Define a plugin function to be called immediately upon init. Plugins are chainable - * and expose the following arguments to the plugin function: - * - * - `app`: the current instance of `Base` - * - `base`: the [first ancestor instance](#base) of `Base` - * - * ```js - * var app = new Base() - * .use(foo) - * .use(bar) - * .use(baz) - * ``` - * @name .use - * @param {Function} `fn` plugin function to call - * @return {Object} Returns the item instance for chaining. - * @api public - */ - - Base.prototype.use = function(fn) { - fn.call(this, this); - return this; - }; - - /** - * The `.define` method is used for adding non-enumerable property on the instance. - * Dot-notation is **not supported** with `define`. - * - * ```js - * // arbitrary `render` function using lodash `template` - * app.define('render', function(str, locals) { - * return _.template(str)(locals); - * }); - * ``` - * @name .define - * @param {String} `key` The name of the property to define. - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Base.prototype.define = function(key, val) { - if (isObject(key)) { - return this.visit('define', key); - } - define(this, key, val); - return this; - }; - - /** - * Mix property `key` onto the Base prototype. If base is inherited using - * `Base.extend` this method will be overridden by a new `mixin` method that will - * only add properties to the prototype of the inheriting application. - * - * ```js - * app.mixin('foo', function() { - * // do stuff - * }); - * ``` - * @name .mixin - * @param {String} `key` - * @param {Object|Array} `val` - * @return {Object} Returns the `base` instance for chaining. - * @api public - */ - - Base.prototype.mixin = function(key, val) { - Base.prototype[key] = val; - return this; - }; - - /** - * Non-enumberable mixin array, used by the static [Base.mixin]() method. - */ - - Base.prototype.mixins = Base.prototype.mixins || []; - - /** - * Getter/setter used when creating nested instances of `Base`, for storing a reference - * to the first ancestor instance. This works by setting an instance of `Base` on the `parent` - * property of a "child" instance. The `base` property defaults to the current instance if - * no `parent` property is defined. - * - * ```js - * // create an instance of `Base`, this is our first ("base") instance - * var first = new Base(); - * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later - * - * // create another instance - * var second = new Base(); - * // create a reference to the first instance (`first`) - * second.parent = first; - * - * // create another instance - * var third = new Base(); - * // create a reference to the previous instance (`second`) - * // repeat this pattern every time a "child" instance is created - * third.parent = second; - * - * // we can always access the first instance using the `base` property - * console.log(first.base.foo); - * //=> 'bar' - * console.log(second.base.foo); - * //=> 'bar' - * console.log(third.base.foo); - * //=> 'bar' - * // and now you know how to get to third base ;) - * ``` - * @name .base - * @api public - */ - - Object.defineProperty(Base.prototype, 'base', { - configurable: true, - get: function() { - return this.parent ? this.parent.base : this; - } - }); - - /** - * Static method for adding global plugin functions that will - * be added to an instance when created. - * - * ```js - * Base.use(function(app) { - * app.foo = 'bar'; - * }); - * var app = new Base(); - * console.log(app.foo); - * //=> 'bar' - * ``` - * @name #use - * @param {Function} `fn` Plugin function to use on each instance. - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'use', function(fn) { - fns.push(fn); - return Base; - }); - - /** - * Run an array of functions by passing each function - * to a method on the given object specified by the given property. - * - * @param {Object} `obj` Object containing method to use. - * @param {String} `prop` Name of the method on the object to use. - * @param {Array} `arr` Array of functions to pass to the method. - */ - - define(Base, 'run', function(obj, prop, arr) { - var len = arr.length, i = 0; - while (len--) { - obj[prop](arr[i++]); - } - return Base; - }); - - /** - * Static method for inheriting the prototype and static methods of the `Base` class. - * This method greatly simplifies the process of creating inheritance-based applications. - * See [static-extend][] for more details. - * - * ```js - * var extend = cu.extend(Parent); - * Parent.extend(Child); - * - * // optional methods - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @name #extend - * @param {Function} `Ctor` constructor to extend - * @param {Object} `methods` Optional prototype properties to mix in. - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'extend', cu.extend(Base, function(Ctor, Parent) { - Ctor.prototype.mixins = Ctor.prototype.mixins || []; - - define(Ctor, 'mixin', function(fn) { - var mixin = fn(Ctor.prototype, Ctor); - if (typeof mixin === 'function') { - Ctor.prototype.mixins.push(mixin); - } - return Ctor; - }); - - define(Ctor, 'mixins', function(Child) { - Base.run(Child, 'mixin', Ctor.prototype.mixins); - return Ctor; - }); - - Ctor.prototype.mixin = function(key, value) { - Ctor.prototype[key] = value; - return this; - }; - return Base; - })); - - /** - * Used for adding methods to the `Base` prototype, and/or to the prototype of child instances. - * When a mixin function returns a function, the returned function is pushed onto the `.mixins` - * array, making it available to be used on inheriting classes whenever `Base.mixins()` is - * called (e.g. `Base.mixins(Child)`). - * - * ```js - * Base.mixin(function(proto) { - * proto.foo = function(msg) { - * return 'foo ' + msg; - * }; - * }); - * ``` - * @name #mixin - * @param {Function} `fn` Function to call - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'mixin', function(fn) { - var mixin = fn(Base.prototype, Base); - if (typeof mixin === 'function') { - Base.prototype.mixins.push(mixin); - } - return Base; - }); - - /** - * Static method for running global mixin functions against a child constructor. - * Mixins must be registered before calling this method. - * - * ```js - * Base.extend(Child); - * Base.mixins(Child); - * ``` - * @name #mixins - * @param {Function} `Child` Constructor function of a child class - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'mixins', function(Child) { - Base.run(Child, 'mixin', Base.prototype.mixins); - return Base; - }); - - /** - * Similar to `util.inherit`, but copies all static properties, prototype properties, and - * getters/setters from `Provider` to `Receiver`. See [class-utils][]{#inherit} for more details. - * - * ```js - * Base.inherit(Foo, Bar); - * ``` - * @name #inherit - * @param {Function} `Receiver` Receiving (child) constructor - * @param {Function} `Provider` Providing (parent) constructor - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'inherit', cu.inherit); - define(Base, 'bubble', cu.bubble); - return Base; -} - -/** - * Expose `Base` with default settings - */ - -module.exports = namespace(); - -/** - * Allow users to define a namespace - */ - -module.exports.namespace = namespace; - - -/***/ }), -/* 430 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(415); -var Emitter = __webpack_require__(431); -var visit = __webpack_require__(432); -var toPath = __webpack_require__(435); -var union = __webpack_require__(436); -var del = __webpack_require__(440); -var get = __webpack_require__(438); -var has = __webpack_require__(445); -var set = __webpack_require__(448); - -/** - * Create a `Cache` constructor that when instantiated will - * store values on the given `prop`. - * - * ```js - * var Cache = require('cache-base').namespace('data'); - * var cache = new Cache(); - * - * cache.set('foo', 'bar'); - * //=> {data: {foo: 'bar'}} - * ``` - * @param {String} `prop` The property name to use for storing values. - * @return {Function} Returns a custom `Cache` constructor - * @api public - */ - -function namespace(prop) { - - /** - * Create a new `Cache`. Internally the `Cache` constructor is created using - * the `namespace` function, with `cache` defined as the storage object. - * - * ```js - * var app = new Cache(); - * ``` - * @param {Object} `cache` Optionally pass an object to initialize with. - * @constructor - * @api public - */ - - function Cache(cache) { - if (prop) { - this[prop] = {}; - } - if (cache) { - this.set(cache); - } - } - - /** - * Inherit Emitter - */ - - Emitter(Cache.prototype); - - /** - * Assign `value` to `key`. Also emits `set` with - * the key and value. - * - * ```js - * app.on('set', function(key, val) { - * // do something when `set` is emitted - * }); - * - * app.set(key, value); - * - * // also takes an object or array - * app.set({name: 'Halle'}); - * app.set([{foo: 'bar'}, {baz: 'quux'}]); - * console.log(app); - * //=> {name: 'Halle', foo: 'bar', baz: 'quux'} - * ``` - * - * @name .set - * @emits `set` with `key` and `value` as arguments. - * @param {String} `key` - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.set = function(key, val) { - if (Array.isArray(key) && arguments.length === 2) { - key = toPath(key); - } - if (isObject(key) || Array.isArray(key)) { - this.visit('set', key); - } else { - set(prop ? this[prop] : this, key, val); - this.emit('set', key, val); - } - return this; - }; - - /** - * Union `array` to `key`. Also emits `set` with - * the key and value. - * - * ```js - * app.union('a.b', ['foo']); - * app.union('a.b', ['bar']); - * console.log(app.get('a')); - * //=> {b: ['foo', 'bar']} - * ``` - * @name .union - * @param {String} `key` - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.union = function(key, val) { - if (Array.isArray(key) && arguments.length === 2) { - key = toPath(key); - } - var ctx = prop ? this[prop] : this; - union(ctx, key, arrayify(val)); - this.emit('union', val); - return this; - }; - - /** - * Return the value of `key`. Dot notation may be used - * to get [nested property values][get-value]. - * - * ```js - * app.set('a.b.c', 'd'); - * app.get('a.b'); - * //=> {c: 'd'} - * - * app.get(['a', 'b']); - * //=> {c: 'd'} - * ``` - * - * @name .get - * @emits `get` with `key` and `value` as arguments. - * @param {String} `key` The name of the property to get. Dot-notation may be used. - * @return {any} Returns the value of `key` - * @api public - */ - - Cache.prototype.get = function(key) { - key = toPath(arguments); - - var ctx = prop ? this[prop] : this; - var val = get(ctx, key); - - this.emit('get', key, val); - return val; - }; - - /** - * Return true if app has a stored value for `key`, - * false only if value is `undefined`. - * - * ```js - * app.set('foo', 'bar'); - * app.has('foo'); - * //=> true - * ``` - * - * @name .has - * @emits `has` with `key` and true or false as arguments. - * @param {String} `key` - * @return {Boolean} - * @api public - */ - - Cache.prototype.has = function(key) { - key = toPath(arguments); - - var ctx = prop ? this[prop] : this; - var val = get(ctx, key); - - var has = typeof val !== 'undefined'; - this.emit('has', key, has); - return has; - }; - - /** - * Delete one or more properties from the instance. - * - * ```js - * app.del(); // delete all - * // or - * app.del('foo'); - * // or - * app.del(['foo', 'bar']); - * ``` - * @name .del - * @emits `del` with the `key` as the only argument. - * @param {String|Array} `key` Property name or array of property names. - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.del = function(key) { - if (Array.isArray(key)) { - this.visit('del', key); - } else { - del(prop ? this[prop] : this, key); - this.emit('del', key); - } - return this; - }; - - /** - * Reset the entire cache to an empty object. - * - * ```js - * app.clear(); - * ``` - * @api public - */ - - Cache.prototype.clear = function() { - if (prop) { - this[prop] = {}; - } - }; - - /** - * Visit `method` over the properties in the given object, or map - * visit over the object-elements in an array. - * - * @name .visit - * @param {String} `method` The name of the `base` method to call. - * @param {Object|Array} `val` The object or array to iterate over. - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.visit = function(method, val) { - visit(this, method, val); - return this; - }; - - return Cache; -} - -/** - * Cast val to an array - */ - -function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -} - -/** - * Expose `Cache` - */ - -module.exports = namespace(); - -/** - * Expose `Cache.namespace` - */ - -module.exports.namespace = namespace; - - -/***/ }), -/* 431 */ -/***/ (function(module, exports, __webpack_require__) { - - -/** - * Expose `Emitter`. - */ - -if (true) { - module.exports = Emitter; -} - -/** - * Initialize a new `Emitter`. - * - * @api public - */ - -function Emitter(obj) { - if (obj) return mixin(obj); -}; - -/** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private - */ - -function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; -} - -/** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.on = -Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks['$' + event] = this._callbacks['$' + event] || []) - .push(fn); - return this; -}; - -/** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.once = function(event, fn){ - function on() { - this.off(event, on); - fn.apply(this, arguments); - } - - on.fn = fn; - this.on(event, on); - return this; -}; - -/** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.off = -Emitter.prototype.removeListener = -Emitter.prototype.removeAllListeners = -Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; - } - - // specific event - var callbacks = this._callbacks['$' + event]; - if (!callbacks) return this; - - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks['$' + event]; - return this; - } - - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } - } - return this; -}; - -/** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} - */ - -Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - var args = [].slice.call(arguments, 1) - , callbacks = this._callbacks['$' + event]; - - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); - } - } - - return this; -}; - -/** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public - */ - -Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks['$' + event] || []; -}; - -/** - * Check if this emitter has `event` handlers. - * - * @param {String} event - * @return {Boolean} - * @api public - */ - -Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; -}; - - -/***/ }), -/* 432 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * collection-visit - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var visit = __webpack_require__(433); -var mapVisit = __webpack_require__(434); - -module.exports = function(collection, method, val) { - var result; - - if (typeof val === 'string' && (method in collection)) { - var args = [].slice.call(arguments, 2); - result = collection[method].apply(collection, args); - } else if (Array.isArray(val)) { - result = mapVisit.apply(null, arguments); - } else { - result = visit.apply(null, arguments); - } - - if (typeof result !== 'undefined') { - return result; - } - - return collection; -}; - - -/***/ }), -/* 433 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * object-visit - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isObject = __webpack_require__(415); - -module.exports = function visit(thisArg, method, target, val) { - if (!isObject(thisArg) && typeof thisArg !== 'function') { - throw new Error('object-visit expects `thisArg` to be an object.'); - } - - if (typeof method !== 'string') { - throw new Error('object-visit expects `method` name to be a string'); - } - - if (typeof thisArg[method] !== 'function') { - return thisArg; - } - - var args = [].slice.call(arguments, 3); - target = target || {}; - - for (var key in target) { - var arr = [key, target[key]].concat(args); - thisArg[method].apply(thisArg, arr); - } - return thisArg; -}; - - -/***/ }), -/* 434 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var util = __webpack_require__(29); -var visit = __webpack_require__(433); - -/** - * Map `visit` over an array of objects. - * - * @param {Object} `collection` The context in which to invoke `method` - * @param {String} `method` Name of the method to call on `collection` - * @param {Object} `arr` Array of objects. - */ - -module.exports = function mapVisit(collection, method, val) { - if (isObject(val)) { - return visit.apply(null, arguments); - } - - if (!Array.isArray(val)) { - throw new TypeError('expected an array: ' + util.inspect(val)); - } - - var args = [].slice.call(arguments, 3); - - for (var i = 0; i < val.length; i++) { - var ele = val[i]; - if (isObject(ele)) { - visit.apply(null, [collection, method, ele].concat(args)); - } else { - collection[method].apply(collection, [ele].concat(args)); - } - } -}; - -function isObject(val) { - return val && (typeof val === 'function' || (!Array.isArray(val) && typeof val === 'object')); -} - - -/***/ }), -/* 435 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * to-object-path - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(420); - -module.exports = function toPath(args) { - if (typeOf(args) !== 'arguments') { - args = arguments; - } - return filter(args).join('.'); -}; - -function filter(arr) { - var len = arr.length; - var idx = -1; - var res = []; - - while (++idx < len) { - var ele = arr[idx]; - if (typeOf(ele) === 'arguments' || Array.isArray(ele)) { - res.push.apply(res, filter(ele)); - } else if (typeof ele === 'string') { - res.push(ele); - } - } - return res; -} - - -/***/ }), -/* 436 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(399); -var union = __webpack_require__(437); -var get = __webpack_require__(438); -var set = __webpack_require__(439); - -module.exports = function unionValue(obj, prop, value) { - if (!isObject(obj)) { - throw new TypeError('union-value expects the first argument to be an object.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('union-value expects `prop` to be a string.'); - } - - var arr = arrayify(get(obj, prop)); - set(obj, prop, union(arr, arrayify(value))); - return obj; -}; - -function arrayify(val) { - if (val === null || typeof val === 'undefined') { - return []; - } - if (Array.isArray(val)) { - return val; - } - return [val]; -} - - -/***/ }), -/* 437 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function union(init) { - if (!Array.isArray(init)) { - throw new TypeError('arr-union expects the first argument to be an array.'); - } - - var len = arguments.length; - var i = 0; - - while (++i < len) { - var arg = arguments[i]; - if (!arg) continue; - - if (!Array.isArray(arg)) { - arg = [arg]; - } - - for (var j = 0; j < arg.length; j++) { - var ele = arg[j]; - - if (init.indexOf(ele) >= 0) { - continue; - } - init.push(ele); - } - } - return init; -}; - - -/***/ }), -/* 438 */ -/***/ (function(module, exports) { - -/*! - * get-value - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -module.exports = function(obj, prop, a, b, c) { - if (!isObject(obj) || !prop) { - return obj; - } - - prop = toString(prop); - - // allowing for multiple properties to be passed as - // a string or array, but much faster (3-4x) than doing - // `[].slice.call(arguments)` - if (a) prop += '.' + toString(a); - if (b) prop += '.' + toString(b); - if (c) prop += '.' + toString(c); - - if (prop in obj) { - return obj[prop]; - } - - var segs = prop.split('.'); - var len = segs.length; - var i = -1; - - while (obj && (++i < len)) { - var key = segs[i]; - while (key[key.length - 1] === '\\') { - key = key.slice(0, -1) + '.' + segs[++i]; - } - obj = obj[key]; - } - return obj; -}; - -function isObject(val) { - return val !== null && (typeof val === 'object' || typeof val === 'function'); -} - -function toString(val) { - if (!val) return ''; - if (Array.isArray(val)) { - return val.join('.'); - } - return val; -} - - -/***/ }), -/* 439 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * set-value +/** + * Returns true if the given node is a "*.close" node. * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var toPath = __webpack_require__(435); -var extend = __webpack_require__(398); -var isPlainObject = __webpack_require__(414); -var isObject = __webpack_require__(399); - -module.exports = function(obj, path, val) { - if (!isObject(obj)) { - return obj; - } - - if (Array.isArray(path)) { - path = toPath(path); - } - - if (typeof path !== 'string') { - return obj; - } - - var segs = path.split('.'); - var len = segs.length, i = -1; - var res = obj; - var last; - - while (++i < len) { - var key = segs[i]; - - while (key[key.length - 1] === '\\') { - key = key.slice(0, -1) + '.' + segs[++i]; - } - - if (i === len - 1) { - last = key; - break; - } - - if (!isObject(obj[key])) { - obj[key] = {}; - } - obj = obj[key]; - } - - if (obj.hasOwnProperty(last) && isObject(obj[last])) { - if (isPlainObject(val)) { - extend(obj[last], val); - } else { - obj[last] = val; - } - - } else { - obj[last] = val; - } - return res; -}; - - - -/***/ }), -/* 440 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * unset-value + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({type: 'brace'}); + * var open = new Node({type: 'brace.open'}); + * var close = new Node({type: 'brace.close'}); * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. + * console.log(utils.isClose(brace)); // false + * console.log(utils.isClose(open)); // false + * console.log(utils.isClose(close)); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public */ - - -var isObject = __webpack_require__(415); -var has = __webpack_require__(441); - -module.exports = function unset(obj, prop) { - if (!isObject(obj)) { - throw new TypeError('expected an object.'); - } - if (obj.hasOwnProperty(prop)) { - delete obj[prop]; - return true; - } - - if (has(obj, prop)) { - var segs = prop.split('.'); - var last = segs.pop(); - while (segs.length && segs[segs.length - 1].slice(-1) === '\\') { - last = segs.pop().slice(0, -1) + '.' + last; - } - while (segs.length) obj = obj[prop = segs.shift()]; - return (delete obj[last]); - } - return true; +utils.isClose = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + return node.type.slice(-6) === '.close'; }; - -/***/ }), -/* 441 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-value +/** + * Returns true if `node.nodes` **has** an `.open` node * - * Copyright (c) 2014-2016, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isObject = __webpack_require__(442); -var hasValues = __webpack_require__(444); -var get = __webpack_require__(438); - -module.exports = function(obj, prop, noZero) { - if (isObject(obj)) { - return hasValues(get(obj, prop), noZero); - } - return hasValues(obj, prop); -}; - - -/***/ }), -/* 442 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * isobject + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({ + * type: 'brace', + * nodes: [] + * }); * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isArray = __webpack_require__(443); - -module.exports = function isObject(val) { - return val != null && typeof val === 'object' && isArray(val) === false; -}; - - -/***/ }), -/* 443 */ -/***/ (function(module, exports) { - -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - - -/***/ }), -/* 444 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-values + * var open = new Node({type: 'brace.open'}); + * console.log(utils.hasOpen(brace)); // false * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. + * brace.pushNode(open); + * console.log(utils.hasOpen(brace)); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public */ - - -module.exports = function hasValue(o, noZero) { - if (o === null || o === undefined) { - return false; - } - - if (typeof o === 'boolean') { - return true; - } - - if (typeof o === 'number') { - if (o === 0 && noZero === true) { - return false; - } - return true; - } - - if (o.length !== undefined) { - return o.length !== 0; - } - - for (var key in o) { - if (o.hasOwnProperty(key)) { - return true; - } +utils.hasOpen = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + var first = node.first || node.nodes ? node.nodes[0] : null; + if (utils.isNode(first)) { + return first.type === node.type + '.open'; } return false; }; - -/***/ }), -/* 445 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-value +/** + * Returns true if `node.nodes` **has** a `.close` node * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isObject = __webpack_require__(415); -var hasValues = __webpack_require__(446); -var get = __webpack_require__(438); - -module.exports = function(val, prop) { - return hasValues(isObject(val) && prop ? get(val, prop) : val); -}; - - -/***/ }), -/* 446 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-values + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({ + * type: 'brace', + * nodes: [] + * }); * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. + * var close = new Node({type: 'brace.close'}); + * console.log(utils.hasClose(brace)); // false + * + * brace.pushNode(close); + * console.log(utils.hasClose(brace)); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public */ - - -var typeOf = __webpack_require__(447); -var isNumber = __webpack_require__(419); - -module.exports = function hasValue(val) { - // is-number checks for NaN and other edge cases - if (isNumber(val)) { - return true; - } - - switch (typeOf(val)) { - case 'null': - case 'boolean': - case 'function': - return true; - case 'string': - case 'arguments': - return val.length !== 0; - case 'error': - return val.message !== ''; - case 'array': - var len = val.length; - if (len === 0) { - return false; - } - for (var i = 0; i < len; i++) { - if (hasValue(val[i])) { - return true; - } - } - return false; - case 'file': - case 'map': - case 'set': - return val.size !== 0; - case 'object': - var keys = Object.keys(val); - if (keys.length === 0) { - return false; - } - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (hasValue(val[key])) { - return true; - } - } - return false; - default: { - return false; - } +utils.hasClose = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + var last = node.last || node.nodes ? node.nodes[node.nodes.length - 1] : null; + if (utils.isNode(last)) { + return last.type === node.type + '.close'; } + return false; }; +/** + * Returns true if `node.nodes` has both `.open` and `.close` nodes + * + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({ + * type: 'brace', + * nodes: [] + * }); + * + * var open = new Node({type: 'brace.open'}); + * var close = new Node({type: 'brace.close'}); + * console.log(utils.hasOpen(brace)); // false + * console.log(utils.hasClose(brace)); // false + * + * brace.pushNode(open); + * brace.pushNode(close); + * console.log(utils.hasOpen(brace)); // true + * console.log(utils.hasClose(brace)); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public + */ -/***/ }), -/* 447 */ -/***/ (function(module, exports, __webpack_require__) { - -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; +utils.hasOpenAndClose = function(node) { + return utils.hasOpen(node) && utils.hasClose(node); +}; /** - * Get the native `typeof` a value. + * Push the given `node` onto the `state.inside` array for the + * given type. This array is used as a specialized "stack" for + * only the given `node.type`. * - * @param {*} `val` - * @return {*} Native javascript type + * ```js + * var state = { inside: {}}; + * var node = new Node({type: 'brace'}); + * utils.addType(state, node); + * console.log(state.inside); + * //=> { brace: [{type: 'brace'}] } + * ``` + * @param {Object} `state` The `compiler.state` object or custom state object. + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Array} Returns the `state.inside` stack for the given type. + * @api public */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; +utils.addType = function(state, node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isObject(state), 'expected state to be an object'); + + var type = node.parent + ? node.parent.type + : node.type.replace(/\.open$/, ''); + + if (!state.hasOwnProperty('inside')) { + state.inside = {}; } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; + if (!state.inside.hasOwnProperty(type)) { + state.inside[type] = []; } - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } + var arr = state.inside[type]; + arr.push(node); + return arr; +}; - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } +/** + * Remove the given `node` from the `state.inside` array for the + * given type. This array is used as a specialized "stack" for + * only the given `node.type`. + * + * ```js + * var state = { inside: {}}; + * var node = new Node({type: 'brace'}); + * utils.addType(state, node); + * console.log(state.inside); + * //=> { brace: [{type: 'brace'}] } + * utils.removeType(state, node); + * //=> { brace: [] } + * ``` + * @param {Object} `state` The `compiler.state` object or custom state object. + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Array} Returns the `state.inside` stack for the given type. + * @api public + */ - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } +utils.removeType = function(state, node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isObject(state), 'expected state to be an object'); - // other objects - var type = toString.call(val); + var type = node.parent + ? node.parent.type + : node.type.replace(/\.close$/, ''); - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; + if (state.inside.hasOwnProperty(type)) { + return state.inside[type].pop(); } +}; - // buffer - if (isBuffer(val)) { - return 'buffer'; - } +/** + * Returns true if `node.val` is an empty string, or `node.nodes` does + * not contain any non-empty text nodes. + * + * ```js + * var node = new Node({type: 'text'}); + * utils.isEmpty(node); //=> true + * node.val = 'foo'; + * utils.isEmpty(node); //=> false + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `fn` + * @return {Boolean} + * @api public + */ - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } +utils.isEmpty = function(node, fn) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; + if (!Array.isArray(node.nodes)) { + if (node.type !== 'text') { + return true; + } + if (typeof fn === 'function') { + return fn(node, node.parent); + } + return !utils.trim(node.val); } - if (type === '[object Float64Array]') { - return 'float64array'; + + for (var i = 0; i < node.nodes.length; i++) { + var child = node.nodes[i]; + if (utils.isOpen(child) || utils.isClose(child)) { + continue; + } + if (!utils.isEmpty(child, fn)) { + return false; + } } - // must be a plain object - return 'object'; + return true; }; - -/***/ }), -/* 448 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * set-value +/** + * Returns true if the `state.inside` stack for the given type exists + * and has one or more nodes on it. * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var state = { inside: {}}; + * var node = new Node({type: 'brace'}); + * console.log(utils.isInsideType(state, 'brace')); //=> false + * utils.addType(state, node); + * console.log(utils.isInsideType(state, 'brace')); //=> true + * utils.removeType(state, node); + * console.log(utils.isInsideType(state, 'brace')); //=> false + * ``` + * @param {Object} `state` + * @param {String} `type` + * @return {Boolean} + * @api public */ +utils.isInsideType = function(state, type) { + assert(isObject(state), 'expected state to be an object'); + assert(isString(type), 'expected type to be a string'); - -var split = __webpack_require__(411); -var extend = __webpack_require__(398); -var isPlainObject = __webpack_require__(414); -var isObject = __webpack_require__(399); - -module.exports = function(obj, prop, val) { - if (!isObject(obj)) { - return obj; + if (!state.hasOwnProperty('inside')) { + return false; } - if (Array.isArray(prop)) { - prop = [].concat.apply([], prop).join('.'); + if (!state.inside.hasOwnProperty(type)) { + return false; } - if (typeof prop !== 'string') { - return obj; - } + return state.inside[type].length > 0; +}; - var keys = split(prop, {sep: '.', brackets: true}); - var len = keys.length; - var idx = -1; - var current = obj; +/** + * Returns true if `node` is either a child or grand-child of the given `type`, + * or `state.inside[type]` is a non-empty array. + * + * ```js + * var state = { inside: {}}; + * var node = new Node({type: 'brace'}); + * var open = new Node({type: 'brace.open'}); + * console.log(utils.isInside(state, open, 'brace')); //=> false + * utils.pushNode(node, open); + * console.log(utils.isInside(state, open, 'brace')); //=> true + * ``` + * @param {Object} `state` Either the `compiler.state` object, if it exists, or a user-supplied state object. + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {String} `type` The `node.type` to check for. + * @return {Boolean} + * @api public + */ - while (++idx < len) { - var key = keys[idx]; - if (idx !== len - 1) { - if (!isObject(current[key])) { - current[key] = {}; - } - current = current[key]; - continue; - } +utils.isInside = function(state, node, type) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isObject(state), 'expected state to be an object'); - if (isPlainObject(current[key]) && isPlainObject(val)) { - current[key] = extend({}, current[key], val); - } else { - current[key] = val; + if (Array.isArray(type)) { + for (var i = 0; i < type.length; i++) { + if (utils.isInside(state, node, type[i])) { + return true; + } } + return false; } - return obj; -}; - - -/***/ }), -/* 449 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; + var parent = node.parent; + if (typeof type === 'string') { + return (parent && parent.type === type) || utils.isInsideType(state, type); + } + if (typeOf(type) === 'regexp') { + if (parent && parent.type && type.test(parent.type)) { + return true; + } -var isExtendable = __webpack_require__(450); -var forIn = __webpack_require__(451); + var keys = Object.keys(state.inside); + var len = keys.length; + var idx = -1; + while (++idx < len) { + var key = keys[idx]; + var val = state.inside[key]; -function mixinDeep(target, objects) { - var len = arguments.length, i = 0; - while (++i < len) { - var obj = arguments[i]; - if (isObject(obj)) { - forIn(obj, copy, target); + if (Array.isArray(val) && val.length !== 0 && type.test(key)) { + return true; + } } } - return target; -} + return false; +}; /** - * Copy properties from the source object to the - * target object. + * Get the last `n` element from the given `array`. Used for getting + * a node from `node.nodes.` * - * @param {*} `val` - * @param {String} `key` + * @param {Array} `array` + * @param {Number} `n` + * @return {undefined} + * @api public */ -function copy(val, key) { - var obj = this[key]; - if (isObject(val) && isObject(obj)) { - mixinDeep(obj, val); - } else { - this[key] = val; - } -} +utils.last = function(arr, n) { + return arr[arr.length - (n || 1)]; +}; /** - * Returns true if `val` is an object or function. + * Cast the given `val` to an array. * - * @param {any} val - * @return {Boolean} + * ```js + * console.log(utils.arrayify('')); + * //=> [] + * console.log(utils.arrayify('foo')); + * //=> ['foo'] + * console.log(utils.arrayify(['foo'])); + * //=> ['foo'] + * ``` + * @param {any} `val` + * @return {Array} + * @api public */ -function isObject(val) { - return isExtendable(val) && !Array.isArray(val); -} +utils.arrayify = function(val) { + if (typeof val === 'string' && val !== '') { + return [val]; + } + if (!Array.isArray(val)) { + return []; + } + return val; +}; /** - * Expose `mixinDeep` + * Convert the given `val` to a string by joining with `,`. Useful + * for creating a cheerio/CSS/DOM-style selector from a list of strings. + * + * @param {any} `val` + * @return {Array} + * @api public */ -module.exports = mixinDeep; - - -/***/ }), -/* 450 */ -/***/ (function(module, exports, __webpack_require__) { +utils.stringify = function(val) { + return utils.arrayify(val).join(','); +}; -"use strict"; -/*! - * is-extendable +/** + * Ensure that the given value is a string and call `.trim()` on it, + * or return an empty string. * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * @param {String} `str` + * @return {String} + * @api public */ - - -var isPlainObject = __webpack_require__(414); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); +utils.trim = function(str) { + return typeof str === 'string' ? str.trim() : ''; }; +/** + * Return true if val is an object + */ -/***/ }), -/* 451 */ -/***/ (function(module, exports, __webpack_require__) { +function isObject(val) { + return typeOf(val) === 'object'; +} -"use strict"; -/*! - * for-in - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. +/** + * Return true if val is a string */ +function isString(val) { + return typeof val === 'string'; +} +/** + * Return true if val is a function + */ -module.exports = function forIn(obj, fn, thisArg) { - for (var key in obj) { - if (fn.call(thisArg, obj[key], key, obj) === false) { - break; - } - } -}; +function isFunction(val) { + return typeof val === 'function'; +} +/** + * Return true if val is an array + */ -/***/ }), -/* 452 */ -/***/ (function(module, exports) { +function isArray(val) { + return Array.isArray(val); +} -/*! - * pascalcase - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. +/** + * Shim to ensure the `.append` methods work with any version of snapdragon */ -function pascalcase(str) { - if (typeof str !== 'string') { - throw new TypeError('expected a string.'); +function append(compiler, val, node) { + if (typeof compiler.append !== 'function') { + return compiler.emit(val, node); } - str = str.replace(/([A-Z])/g, ' $1'); - if (str.length === 1) { return str.toUpperCase(); } - str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); - str = str.charAt(0).toUpperCase() + str.slice(1); - return str.replace(/[\W_]+(\w|$)/g, function (_, ch) { - return ch.toUpperCase(); - }); + return compiler.append(val, node); } -module.exports = pascalcase; +/** + * Simplified assertion. Throws an error is `val` is falsey. + */ + +function assert(val, message) { + if (!val) throw new Error(message); +} /***/ }), -/* 453 */ +/* 423 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var util = __webpack_require__(29); -var utils = __webpack_require__(454); - -/** - * Expose class utils - */ - -var cu = module.exports; +var extend = __webpack_require__(394); +var Snapdragon = __webpack_require__(424); +var compilers = __webpack_require__(398); +var parsers = __webpack_require__(413); +var utils = __webpack_require__(399); /** - * Expose class utils: `cu` + * Customize Snapdragon parser and renderer */ -cu.isObject = function isObject(val) { - return utils.isObj(val) || typeof val === 'function'; -}; +function Braces(options) { + this.options = extend({}, options); +} /** - * Returns true if an array has any of the given elements, or an - * object has any of the give keys. - * - * ```js - * cu.has(['a', 'b', 'c'], 'c'); - * //=> true - * - * cu.has(['a', 'b', 'c'], ['c', 'z']); - * //=> true - * - * cu.has({a: 'b', c: 'd'}, ['c', 'z']); - * //=> true - * ``` - * @param {Object} `obj` - * @param {String|Array} `val` - * @return {Boolean} - * @api public + * Initialize braces */ -cu.has = function has(obj, val) { - val = cu.arrayify(val); - var len = val.length; +Braces.prototype.init = function(options) { + if (this.isInitialized) return; + this.isInitialized = true; + var opts = utils.createOptions({}, this.options, options); + this.snapdragon = this.options.snapdragon || new Snapdragon(opts); + this.compiler = this.snapdragon.compiler; + this.parser = this.snapdragon.parser; - if (cu.isObject(obj)) { - for (var key in obj) { - if (val.indexOf(key) > -1) { - return true; - } - } + compilers(this.snapdragon, opts); + parsers(this.snapdragon, opts); - var keys = cu.nativeKeys(obj); - return cu.has(keys, val); - } + /** + * Call Snapdragon `.parse` method. When AST is returned, we check to + * see if any unclosed braces are left on the stack and, if so, we iterate + * over the stack and correct the AST so that compilers are called in the correct + * order and unbalance braces are properly escaped. + */ - if (Array.isArray(obj)) { - var arr = obj; - while (len--) { - if (arr.indexOf(val[len]) > -1) { - return true; - } + utils.define(this.snapdragon, 'parse', function(pattern, options) { + var parsed = Snapdragon.prototype.parse.apply(this, arguments); + this.parser.ast.input = pattern; + + var stack = this.parser.stack; + while (stack.length) { + addParent({type: 'brace.close', val: ''}, stack.pop()); } - return false; - } - throw new TypeError('expected an array or object.'); + function addParent(node, parent) { + utils.define(node, 'parent', parent); + parent.nodes.push(node); + } + + // add non-enumerable parser reference + utils.define(parsed, 'parser', this.parser); + return parsed; + }); }; /** - * Returns true if an array or object has all of the given values. - * - * ```js - * cu.hasAll(['a', 'b', 'c'], 'c'); - * //=> true - * - * cu.hasAll(['a', 'b', 'c'], ['c', 'z']); - * //=> false - * - * cu.hasAll({a: 'b', c: 'd'}, ['c', 'z']); - * //=> false - * ``` - * @param {Object|Array} `val` - * @param {String|Array} `values` - * @return {Boolean} - * @api public + * Decorate `.parse` method */ -cu.hasAll = function hasAll(val, values) { - values = cu.arrayify(values); - var len = values.length; - while (len--) { - if (!cu.has(val, values[len])) { - return false; - } - } - return true; +Braces.prototype.parse = function(ast, options) { + if (ast && typeof ast === 'object' && ast.nodes) return ast; + this.init(options); + return this.snapdragon.parse(ast, options); }; /** - * Cast the given value to an array. - * - * ```js - * cu.arrayify('foo'); - * //=> ['foo'] - * - * cu.arrayify(['foo']); - * //=> ['foo'] - * ``` - * - * @param {String|Array} `val` - * @return {Array} - * @api public + * Decorate `.compile` method */ -cu.arrayify = function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; +Braces.prototype.compile = function(ast, options) { + if (typeof ast === 'string') { + ast = this.parse(ast, options); + } else { + this.init(options); + } + return this.snapdragon.compile(ast, options); }; /** - * Noop + * Expand */ -cu.noop = function noop() { - return; +Braces.prototype.expand = function(pattern) { + var ast = this.parse(pattern, {expand: true}); + return this.compile(ast, {expand: true}); }; /** - * Returns the first argument passed to the function. + * Optimize */ -cu.identity = function identity(val) { - return val; +Braces.prototype.optimize = function(pattern) { + var ast = this.parse(pattern, {optimize: true}); + return this.compile(ast, {optimize: true}); }; /** - * Returns true if a value has a `contructor` - * - * ```js - * cu.hasConstructor({}); - * //=> true - * - * cu.hasConstructor(Object.create(null)); - * //=> false - * ``` - * @param {Object} `value` - * @return {Boolean} - * @api public + * Expose `Braces` */ -cu.hasConstructor = function hasConstructor(val) { - return cu.isObject(val) && typeof val.constructor !== 'undefined'; -}; +module.exports = Braces; + + +/***/ }), +/* 424 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var Base = __webpack_require__(425); +var define = __webpack_require__(386); +var Compiler = __webpack_require__(455); +var Parser = __webpack_require__(485); +var utils = __webpack_require__(465); +var regexCache = {}; +var cache = {}; /** - * Get the native `ownPropertyNames` from the constructor of the - * given `object`. An empty array is returned if the object does - * not have a constructor. + * Create a new instance of `Snapdragon` with the given `options`. * * ```js - * cu.nativeKeys({a: 'b', b: 'c', c: 'd'}) - * //=> ['a', 'b', 'c'] - * - * cu.nativeKeys(function(){}) - * //=> ['length', 'caller'] + * var snapdragon = new Snapdragon(); * ``` * - * @param {Object} `obj` Object that has a `constructor`. - * @return {Array} Array of keys. + * @param {Object} `options` * @api public */ -cu.nativeKeys = function nativeKeys(val) { - if (!cu.hasConstructor(val)) return []; - return Object.getOwnPropertyNames(val); -}; +function Snapdragon(options) { + Base.call(this, null, options); + this.options = utils.extend({source: 'string'}, this.options); + this.compiler = new Compiler(this.options); + this.parser = new Parser(this.options); + + Object.defineProperty(this, 'compilers', { + get: function() { + return this.compiler.compilers; + } + }); + + Object.defineProperty(this, 'parsers', { + get: function() { + return this.parser.parsers; + } + }); + + Object.defineProperty(this, 'regex', { + get: function() { + return this.parser.regex; + } + }); +} /** - * Returns property descriptor `key` if it's an "own" property - * of the given object. - * - * ```js - * function App() {} - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this).length; - * } - * }); - * cu.getDescriptor(App.prototype, 'count'); - * // returns: - * // { - * // get: [Function], - * // set: undefined, - * // enumerable: false, - * // configurable: false - * // } - * ``` - * - * @param {Object} `obj` - * @param {String} `key` - * @return {Object} Returns descriptor `key` - * @api public + * Inherit Base */ -cu.getDescriptor = function getDescriptor(obj, key) { - if (!cu.isObject(obj)) { - throw new TypeError('expected an object.'); - } - if (typeof key !== 'string') { - throw new TypeError('expected key to be a string.'); - } - return Object.getOwnPropertyDescriptor(obj, key); -}; +Base.extend(Snapdragon); /** - * Copy a descriptor from one object to another. + * Add a parser to `snapdragon.parsers` for capturing the given `type` using + * the specified regex or parser function. A function is useful if you need + * to customize how the token is created and/or have access to the parser + * instance to check options, etc. * * ```js - * function App() {} - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this).length; - * } - * }); - * var obj = {}; - * cu.copyDescriptor(obj, App.prototype, 'count'); + * snapdragon + * .capture('slash', /^\//) + * .capture('dot', function() { + * var pos = this.position(); + * var m = this.match(/^\./); + * if (!m) return; + * return pos({ + * type: 'dot', + * val: m[0] + * }); + * }); * ``` - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String} `name` - * @return {Object} + * @param {String} `type` + * @param {RegExp|Function} `regex` + * @return {Object} Returns the parser instance for chaining * @api public */ -cu.copyDescriptor = function copyDescriptor(receiver, provider, name) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - if (typeof name !== 'string') { - throw new TypeError('expected name to be a string.'); - } - - var val = cu.getDescriptor(provider, name); - if (val) Object.defineProperty(receiver, name, val); +Snapdragon.prototype.capture = function() { + return this.parser.capture.apply(this.parser, arguments); }; /** - * Copy static properties, prototype properties, and descriptors - * from one object to another. + * Register a plugin `fn`. * - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} + * ```js + * var snapdragon = new Snapdgragon([options]); + * snapdragon.use(function() { + * console.log(this); //<= snapdragon instance + * console.log(this.parser); //<= parser instance + * console.log(this.compiler); //<= compiler instance + * }); + * ``` + * @param {Object} `fn` * @api public */ -cu.copy = function copy(receiver, provider, omit) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - var props = Object.getOwnPropertyNames(provider); - var keys = Object.keys(provider); - var len = props.length, - key; - omit = cu.arrayify(omit); - - while (len--) { - key = props[len]; - - if (cu.has(keys, key)) { - utils.define(receiver, key, provider[key]); - } else if (!(key in receiver) && !cu.has(omit, key)) { - cu.copyDescriptor(receiver, provider, key); - } - } +Snapdragon.prototype.use = function(fn) { + fn.call(this, this); + return this; }; /** - * Inherit the static properties, prototype properties, and descriptors - * from of an object. + * Parse the given `str`. * - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} + * ```js + * var snapdragon = new Snapdgragon([options]); + * // register parsers + * snapdragon.parser.use(function() {}); + * + * // parse + * var ast = snapdragon.parse('foo/bar'); + * console.log(ast); + * ``` + * @param {String} `str` + * @param {Object} `options` Set `options.sourcemap` to true to enable source maps. + * @return {Object} Returns an AST. * @api public */ -cu.inherit = function inherit(receiver, provider, omit) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - - var keys = []; - for (var key in provider) { - keys.push(key); - receiver[key] = provider[key]; - } - - keys = keys.concat(cu.arrayify(omit)); +Snapdragon.prototype.parse = function(str, options) { + this.options = utils.extend({}, this.options, options); + var parsed = this.parser.parse(str, this.options); - var a = provider.prototype || provider; - var b = receiver.prototype || receiver; - cu.copy(b, a, keys); + // add non-enumerable parser reference + define(parsed, 'parser', this.parser); + return parsed; }; /** - * Returns a function for extending the static properties, - * prototype properties, and descriptors from the `Parent` - * constructor onto `Child` constructors. + * Compile the given `AST`. * * ```js - * var extend = cu.extend(Parent); - * Parent.extend(Child); + * var snapdragon = new Snapdgragon([options]); + * // register plugins + * snapdragon.use(function() {}); + * // register parser plugins + * snapdragon.parser.use(function() {}); + * // register compiler plugins + * snapdragon.compiler.use(function() {}); * - * // optional methods - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); + * // parse + * var ast = snapdragon.parse('foo/bar'); + * + * // compile + * var res = snapdragon.compile(ast); + * console.log(res.output); * ``` - * @param {Function} `Parent` Parent ctor - * @param {Function} `extend` Optional extend function to handle custom extensions. Useful when updating methods that require a specific prototype. - * @param {Function} `Child` Child ctor - * @param {Object} `proto` Optionally pass additional prototype properties to inherit. - * @return {Object} + * @param {Object} `ast` + * @param {Object} `options` + * @return {Object} Returns an object with an `output` property with the rendered string. * @api public */ -cu.extend = function() { - // keep it lazy, instead of assigning to `cu.extend` - return utils.staticExtend.apply(null, arguments); -}; - -/** - * Bubble up events emitted from static methods on the Parent ctor. - * - * @param {Object} `Parent` - * @param {Array} `events` Event names to bubble up - * @api public - */ +Snapdragon.prototype.compile = function(ast, options) { + this.options = utils.extend({}, this.options, options); + var compiled = this.compiler.compile(ast, this.options); -cu.bubble = function(Parent, events) { - events = events || []; - Parent.bubble = function(Child, arr) { - if (Array.isArray(arr)) { - events = utils.union([], events, arr); - } - var len = events.length; - var idx = -1; - while (++idx < len) { - var name = events[idx]; - Parent.on(name, Child.emit.bind(Child, name)); - } - cu.bubble(Child, events); - }; + // add non-enumerable compiler reference + define(compiled, 'compiler', this.compiler); + return compiled; }; - -/***/ }), -/* 454 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = {}; - - - /** - * Lazily required module dependencies + * Expose `Snapdragon` */ -utils.union = __webpack_require__(437); -utils.define = __webpack_require__(455); -utils.isObj = __webpack_require__(415); -utils.staticExtend = __webpack_require__(462); - +module.exports = Snapdragon; /** - * Expose `utils` + * Expose `Parser` and `Compiler` */ -module.exports = utils; +module.exports.Compiler = Compiler; +module.exports.Parser = Parser; /***/ }), -/* 455 */ +/* 425 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * define-property - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ +var util = __webpack_require__(29); +var define = __webpack_require__(426); +var CacheBase = __webpack_require__(427); +var Emitter = __webpack_require__(428); +var isObject = __webpack_require__(404); +var merge = __webpack_require__(446); +var pascal = __webpack_require__(449); +var cu = __webpack_require__(450); -var isDescriptor = __webpack_require__(456); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; +/** + * Optionally define a custom `cache` namespace to use. + */ +function namespace(name) { + var Cache = name ? CacheBase.namespace(name) : CacheBase; + var fns = []; -/***/ }), -/* 456 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Create an instance of `Base` with the given `config` and `options`. + * + * ```js + * // initialize with `config` and `options` + * var app = new Base({isApp: true}, {abc: true}); + * app.set('foo', 'bar'); + * + * // values defined with the given `config` object will be on the root of the instance + * console.log(app.baz); //=> undefined + * console.log(app.foo); //=> 'bar' + * // or use `.get` + * console.log(app.get('isApp')); //=> true + * console.log(app.get('foo')); //=> 'bar' + * + * // values defined with the given `options` object will be on `app.options + * console.log(app.options.abc); //=> true + * ``` + * + * @param {Object} `config` If supplied, this object is passed to [cache-base][] to merge onto the the instance upon instantiation. + * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object. + * @api public + */ -"use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ + function Base(config, options) { + if (!(this instanceof Base)) { + return new Base(config, options); + } + Cache.call(this, config); + this.is('base'); + this.initBase(config, options); + } + /** + * Inherit cache-base + */ + util.inherits(Base, Cache); -var typeOf = __webpack_require__(457); -var isAccessor = __webpack_require__(458); -var isData = __webpack_require__(460); + /** + * Add static emitter methods + */ -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; + Emitter(Base); + /** + * Initialize `Base` defaults with the given `config` object + */ -/***/ }), -/* 457 */ -/***/ (function(module, exports) { + Base.prototype.initBase = function(config, options) { + this.options = merge({}, this.options, options); + this.cache = this.cache || {}; + this.define('registered', {}); + if (name) this[name] = {}; -var toString = Object.prototype.toString; + // make `app._callbacks` non-enumerable + this.define('_callbacks', this._callbacks); + if (isObject(config)) { + this.visit('set', config); + } + Base.run(this, 'use', fns); + }; -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ + /** + * Set the given `name` on `app._name` and `app.is*` properties. Used for doing + * lookups in plugins. + * + * ```js + * app.is('foo'); + * console.log(app._name); + * //=> 'foo' + * console.log(app.isFoo); + * //=> true + * app.is('bar'); + * console.log(app.isFoo); + * //=> true + * console.log(app.isBar); + * //=> true + * console.log(app._name); + * //=> 'bar' + * ``` + * @name .is + * @param {String} `name` + * @return {Boolean} + * @api public + */ -module.exports = function kindOf(val) { - var type = typeof val; + Base.prototype.is = function(name) { + if (typeof name !== 'string') { + throw new TypeError('expected name to be a string'); + } + this.define('is' + pascal(name), true); + this.define('_name', name); + this.define('_appname', name); + return this; + }; - // primitivies - if (type === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (type === 'string' || val instanceof String) { - return 'string'; - } - if (type === 'number' || val instanceof Number) { - return 'number'; - } + /** + * Returns true if a plugin has already been registered on an instance. + * + * Plugin implementors are encouraged to use this first thing in a plugin + * to prevent the plugin from being called more than once on the same + * instance. + * + * ```js + * var base = new Base(); + * base.use(function(app) { + * if (app.isRegistered('myPlugin')) return; + * // do stuff to `app` + * }); + * + * // to also record the plugin as being registered + * base.use(function(app) { + * if (app.isRegistered('myPlugin', true)) return; + * // do stuff to `app` + * }); + * ``` + * @name .isRegistered + * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once. + * @param {String} `name` The plugin name. + * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument. + * @return {Boolean} Returns true if a plugin is already registered. + * @api public + */ - // functions - if (type === 'function' || val instanceof Function) { - if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { - return 'generatorfunction'; + Base.prototype.isRegistered = function(name, register) { + if (this.registered.hasOwnProperty(name)) { + return true; } - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } + if (register !== false) { + this.registered[name] = true; + this.emit('plugin', name); + } + return false; + }; - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } + /** + * Define a plugin function to be called immediately upon init. Plugins are chainable + * and expose the following arguments to the plugin function: + * + * - `app`: the current instance of `Base` + * - `base`: the [first ancestor instance](#base) of `Base` + * + * ```js + * var app = new Base() + * .use(foo) + * .use(bar) + * .use(baz) + * ``` + * @name .use + * @param {Function} `fn` plugin function to call + * @return {Object} Returns the item instance for chaining. + * @api public + */ - // other objects - type = toString.call(val); + Base.prototype.use = function(fn) { + fn.call(this, this); + return this; + }; - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; - } + /** + * The `.define` method is used for adding non-enumerable property on the instance. + * Dot-notation is **not supported** with `define`. + * + * ```js + * // arbitrary `render` function using lodash `template` + * app.define('render', function(str, locals) { + * return _.template(str)(locals); + * }); + * ``` + * @name .define + * @param {String} `key` The name of the property to define. + * @param {any} `value` + * @return {Object} Returns the instance for chaining. + * @api public + */ - // buffer - if (isBuffer(val)) { - return 'buffer'; - } + Base.prototype.define = function(key, val) { + if (isObject(key)) { + return this.visit('define', key); + } + define(this, key, val); + return this; + }; - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - if (type === '[object Map Iterator]') { - return 'mapiterator'; - } - if (type === '[object Set Iterator]') { - return 'setiterator'; - } - if (type === '[object String Iterator]') { - return 'stringiterator'; - } - if (type === '[object Array Iterator]') { - return 'arrayiterator'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } + /** + * Mix property `key` onto the Base prototype. If base is inherited using + * `Base.extend` this method will be overridden by a new `mixin` method that will + * only add properties to the prototype of the inheriting application. + * + * ```js + * app.mixin('foo', function() { + * // do stuff + * }); + * ``` + * @name .mixin + * @param {String} `key` + * @param {Object|Array} `val` + * @return {Object} Returns the `base` instance for chaining. + * @api public + */ - // must be a plain object - return 'object'; -}; + Base.prototype.mixin = function(key, val) { + Base.prototype[key] = val; + return this; + }; -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ + /** + * Non-enumberable mixin array, used by the static [Base.mixin]() method. + */ -function isBuffer(val) { - return val.constructor - && typeof val.constructor.isBuffer === 'function' - && val.constructor.isBuffer(val); -} + Base.prototype.mixins = Base.prototype.mixins || []; + /** + * Getter/setter used when creating nested instances of `Base`, for storing a reference + * to the first ancestor instance. This works by setting an instance of `Base` on the `parent` + * property of a "child" instance. The `base` property defaults to the current instance if + * no `parent` property is defined. + * + * ```js + * // create an instance of `Base`, this is our first ("base") instance + * var first = new Base(); + * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later + * + * // create another instance + * var second = new Base(); + * // create a reference to the first instance (`first`) + * second.parent = first; + * + * // create another instance + * var third = new Base(); + * // create a reference to the previous instance (`second`) + * // repeat this pattern every time a "child" instance is created + * third.parent = second; + * + * // we can always access the first instance using the `base` property + * console.log(first.base.foo); + * //=> 'bar' + * console.log(second.base.foo); + * //=> 'bar' + * console.log(third.base.foo); + * //=> 'bar' + * // and now you know how to get to third base ;) + * ``` + * @name .base + * @api public + */ -/***/ }), -/* 458 */ -/***/ (function(module, exports, __webpack_require__) { + Object.defineProperty(Base.prototype, 'base', { + configurable: true, + get: function() { + return this.parent ? this.parent.base : this; + } + }); -"use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ + /** + * Static method for adding global plugin functions that will + * be added to an instance when created. + * + * ```js + * Base.use(function(app) { + * app.foo = 'bar'; + * }); + * var app = new Base(); + * console.log(app.foo); + * //=> 'bar' + * ``` + * @name #use + * @param {Function} `fn` Plugin function to use on each instance. + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ + define(Base, 'use', function(fn) { + fns.push(fn); + return Base; + }); + /** + * Run an array of functions by passing each function + * to a method on the given object specified by the given property. + * + * @param {Object} `obj` Object containing method to use. + * @param {String} `prop` Name of the method on the object to use. + * @param {Array} `arr` Array of functions to pass to the method. + */ -var typeOf = __webpack_require__(459); + define(Base, 'run', function(obj, prop, arr) { + var len = arr.length, i = 0; + while (len--) { + obj[prop](arr[i++]); + } + return Base; + }); -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; + /** + * Static method for inheriting the prototype and static methods of the `Base` class. + * This method greatly simplifies the process of creating inheritance-based applications. + * See [static-extend][] for more details. + * + * ```js + * var extend = cu.extend(Parent); + * Parent.extend(Child); + * + * // optional methods + * Parent.extend(Child, { + * foo: function() {}, + * bar: function() {} + * }); + * ``` + * @name #extend + * @param {Function} `Ctor` constructor to extend + * @param {Object} `methods` Optional prototype properties to mix in. + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } + define(Base, 'extend', cu.extend(Base, function(Ctor, Parent) { + Ctor.prototype.mixins = Ctor.prototype.mixins || []; - if (typeOf(obj) !== 'object') { - return false; - } + define(Ctor, 'mixin', function(fn) { + var mixin = fn(Ctor.prototype, Ctor); + if (typeof mixin === 'function') { + Ctor.prototype.mixins.push(mixin); + } + return Ctor; + }); - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } + define(Ctor, 'mixins', function(Child) { + Base.run(Child, 'mixin', Ctor.prototype.mixins); + return Ctor; + }); - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } + Ctor.prototype.mixin = function(key, value) { + Ctor.prototype[key] = value; + return this; + }; + return Base; + })); - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } + /** + * Used for adding methods to the `Base` prototype, and/or to the prototype of child instances. + * When a mixin function returns a function, the returned function is pushed onto the `.mixins` + * array, making it available to be used on inheriting classes whenever `Base.mixins()` is + * called (e.g. `Base.mixins(Child)`). + * + * ```js + * Base.mixin(function(proto) { + * proto.foo = function(msg) { + * return 'foo ' + msg; + * }; + * }); + * ``` + * @name #mixin + * @param {Function} `fn` Function to call + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; + define(Base, 'mixin', function(fn) { + var mixin = fn(Base.prototype, Base); + if (typeof mixin === 'function') { + Base.prototype.mixins.push(mixin); } + return Base; + }); + + /** + * Static method for running global mixin functions against a child constructor. + * Mixins must be registered before calling this method. + * + * ```js + * Base.extend(Child); + * Base.mixins(Child); + * ``` + * @name #mixins + * @param {Function} `Child` Constructor function of a child class + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ - if (typeOf(obj[key]) === accessor[key]) { - continue; - } + define(Base, 'mixins', function(Child) { + Base.run(Child, 'mixin', Base.prototype.mixins); + return Base; + }); - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} + /** + * Similar to `util.inherit`, but copies all static properties, prototype properties, and + * getters/setters from `Provider` to `Receiver`. See [class-utils][]{#inherit} for more details. + * + * ```js + * Base.inherit(Foo, Bar); + * ``` + * @name #inherit + * @param {Function} `Receiver` Receiving (child) constructor + * @param {Function} `Provider` Providing (parent) constructor + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); + define(Base, 'inherit', cu.inherit); + define(Base, 'bubble', cu.bubble); + return Base; } /** - * Expose `isAccessorDescriptor` + * Expose `Base` with default settings */ -module.exports = isAccessorDescriptor; - - -/***/ }), -/* 459 */ -/***/ (function(module, exports, __webpack_require__) { - -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; +module.exports = namespace(); /** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type + * Allow users to define a namespace */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - var type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - - // must be a plain object - return 'object'; -}; +module.exports.namespace = namespace; /***/ }), -/* 460 */ +/* 426 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-data-descriptor + * define-property * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -var typeOf = __webpack_require__(461); - -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' -}; - -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; - } +var isDescriptor = __webpack_require__(416); - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; +module.exports = function defineProperty(obj, prop, val) { + if (typeof obj !== 'object' && typeof obj !== 'function') { + throw new TypeError('expected an object or function.'); } - if (!('value' in obj) && !('writable' in obj)) { - return false; + if (typeof prop !== 'string') { + throw new TypeError('expected `prop` to be a string.'); } - for (var key in obj) { - if (key === 'value') continue; - - if (!data.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === data[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } + if (isDescriptor(val) && ('set' in val || 'get' in val)) { + return Object.defineProperty(obj, prop, val); } - return true; -} - -/** - * Expose `isDataDescriptor` - */ -module.exports = isDataDescriptor; + return Object.defineProperty(obj, prop, { + configurable: true, + enumerable: false, + writable: true, + value: val + }); +}; /***/ }), -/* 461 */ +/* 427 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; +"use strict"; + + +var isObject = __webpack_require__(404); +var Emitter = __webpack_require__(428); +var visit = __webpack_require__(429); +var toPath = __webpack_require__(432); +var union = __webpack_require__(433); +var del = __webpack_require__(437); +var get = __webpack_require__(435); +var has = __webpack_require__(442); +var set = __webpack_require__(445); /** - * Get the native `typeof` a value. + * Create a `Cache` constructor that when instantiated will + * store values on the given `prop`. * - * @param {*} `val` - * @return {*} Native javascript type + * ```js + * var Cache = require('cache-base').namespace('data'); + * var cache = new Cache(); + * + * cache.set('foo', 'bar'); + * //=> {data: {foo: 'bar'}} + * ``` + * @param {String} `prop` The property name to use for storing values. + * @return {Function} Returns a custom `Cache` constructor + * @api public */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } +function namespace(prop) { - // other objects - var type = toString.call(val); + /** + * Create a new `Cache`. Internally the `Cache` constructor is created using + * the `namespace` function, with `cache` defined as the storage object. + * + * ```js + * var app = new Cache(); + * ``` + * @param {Object} `cache` Optionally pass an object to initialize with. + * @constructor + * @api public + */ - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; + function Cache(cache) { + if (prop) { + this[prop] = {}; + } + if (cache) { + this.set(cache); + } } - // buffer - if (isBuffer(val)) { - return 'buffer'; - } + /** + * Inherit Emitter + */ - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } + Emitter(Cache.prototype); - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } + /** + * Assign `value` to `key`. Also emits `set` with + * the key and value. + * + * ```js + * app.on('set', function(key, val) { + * // do something when `set` is emitted + * }); + * + * app.set(key, value); + * + * // also takes an object or array + * app.set({name: 'Halle'}); + * app.set([{foo: 'bar'}, {baz: 'quux'}]); + * console.log(app); + * //=> {name: 'Halle', foo: 'bar', baz: 'quux'} + * ``` + * + * @name .set + * @emits `set` with `key` and `value` as arguments. + * @param {String} `key` + * @param {any} `value` + * @return {Object} Returns the instance for chaining. + * @api public + */ - // must be a plain object - return 'object'; -}; + Cache.prototype.set = function(key, val) { + if (Array.isArray(key) && arguments.length === 2) { + key = toPath(key); + } + if (isObject(key) || Array.isArray(key)) { + this.visit('set', key); + } else { + set(prop ? this[prop] : this, key, val); + this.emit('set', key, val); + } + return this; + }; + /** + * Union `array` to `key`. Also emits `set` with + * the key and value. + * + * ```js + * app.union('a.b', ['foo']); + * app.union('a.b', ['bar']); + * console.log(app.get('a')); + * //=> {b: ['foo', 'bar']} + * ``` + * @name .union + * @param {String} `key` + * @param {any} `value` + * @return {Object} Returns the instance for chaining. + * @api public + */ -/***/ }), -/* 462 */ -/***/ (function(module, exports, __webpack_require__) { + Cache.prototype.union = function(key, val) { + if (Array.isArray(key) && arguments.length === 2) { + key = toPath(key); + } + var ctx = prop ? this[prop] : this; + union(ctx, key, arrayify(val)); + this.emit('union', val); + return this; + }; -"use strict"; -/*! - * static-extend - * - * Copyright (c) 2016, Jon Schlinkert. - * Licensed under the MIT License. - */ + /** + * Return the value of `key`. Dot notation may be used + * to get [nested property values][get-value]. + * + * ```js + * app.set('a.b.c', 'd'); + * app.get('a.b'); + * //=> {c: 'd'} + * + * app.get(['a', 'b']); + * //=> {c: 'd'} + * ``` + * + * @name .get + * @emits `get` with `key` and `value` as arguments. + * @param {String} `key` The name of the property to get. Dot-notation may be used. + * @return {any} Returns the value of `key` + * @api public + */ + Cache.prototype.get = function(key) { + key = toPath(arguments); + var ctx = prop ? this[prop] : this; + var val = get(ctx, key); -var copy = __webpack_require__(463); -var define = __webpack_require__(470); -var util = __webpack_require__(29); + this.emit('get', key, val); + return val; + }; -/** - * Returns a function for extending the static properties, - * prototype properties, and descriptors from the `Parent` - * constructor onto `Child` constructors. - * - * ```js - * var extend = require('static-extend'); - * Parent.extend = extend(Parent); - * - * // optionally pass a custom merge function as the second arg - * Parent.extend = extend(Parent, function(Child) { - * Child.prototype.mixin = function(key, val) { - * Child.prototype[key] = val; - * }; - * }); - * - * // extend "child" constructors - * Parent.extend(Child); - * - * // optionally define prototype methods as the second arg - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @param {Function} `Parent` Parent ctor - * @param {Function} `extendFn` Optional extend function for handling any necessary custom merging. Useful when updating methods that require a specific prototype. - * @param {Function} `Child` Child ctor - * @param {Object} `proto` Optionally pass additional prototype properties to inherit. - * @return {Object} - * @api public - */ + /** + * Return true if app has a stored value for `key`, + * false only if value is `undefined`. + * + * ```js + * app.set('foo', 'bar'); + * app.has('foo'); + * //=> true + * ``` + * + * @name .has + * @emits `has` with `key` and true or false as arguments. + * @param {String} `key` + * @return {Boolean} + * @api public + */ -function extend(Parent, extendFn) { - if (typeof Parent !== 'function') { - throw new TypeError('expected Parent to be a function.'); - } + Cache.prototype.has = function(key) { + key = toPath(arguments); - return function(Ctor, proto) { - if (typeof Ctor !== 'function') { - throw new TypeError('expected Ctor to be a function.'); - } + var ctx = prop ? this[prop] : this; + var val = get(ctx, key); - util.inherits(Ctor, Parent); - copy(Ctor, Parent); + var has = typeof val !== 'undefined'; + this.emit('has', key, has); + return has; + }; - // proto can be null or a plain object - if (typeof proto === 'object') { - var obj = Object.create(proto); + /** + * Delete one or more properties from the instance. + * + * ```js + * app.del(); // delete all + * // or + * app.del('foo'); + * // or + * app.del(['foo', 'bar']); + * ``` + * @name .del + * @emits `del` with the `key` as the only argument. + * @param {String|Array} `key` Property name or array of property names. + * @return {Object} Returns the instance for chaining. + * @api public + */ - for (var k in obj) { - Ctor.prototype[k] = obj[k]; - } + Cache.prototype.del = function(key) { + if (Array.isArray(key)) { + this.visit('del', key); + } else { + del(prop ? this[prop] : this, key); + this.emit('del', key); } + return this; + }; - // keep a reference to the parent prototype - define(Ctor.prototype, '_parent_', { - configurable: true, - set: function() {}, - get: function() { - return Parent.prototype; - } - }); + /** + * Reset the entire cache to an empty object. + * + * ```js + * app.clear(); + * ``` + * @api public + */ - if (typeof extendFn === 'function') { - extendFn(Ctor, Parent); + Cache.prototype.clear = function() { + if (prop) { + this[prop] = {}; } - - Ctor.extend = extend(Ctor, extendFn); }; -}; -/** - * Expose `extend` - */ + /** + * Visit `method` over the properties in the given object, or map + * visit over the object-elements in an array. + * + * @name .visit + * @param {String} `method` The name of the `base` method to call. + * @param {Object|Array} `val` The object or array to iterate over. + * @return {Object} Returns the instance for chaining. + * @api public + */ -module.exports = extend; + Cache.prototype.visit = function(method, val) { + visit(this, method, val); + return this; + }; + return Cache; +} -/***/ }), -/* 463 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * Cast val to an array + */ -"use strict"; +function arrayify(val) { + return val ? (Array.isArray(val) ? val : [val]) : []; +} +/** + * Expose `Cache` + */ -var typeOf = __webpack_require__(420); -var copyDescriptor = __webpack_require__(464); -var define = __webpack_require__(465); +module.exports = namespace(); /** - * Copy static properties, prototype properties, and descriptors from one object to another. - * - * ```js - * function App() {} - * var proto = App.prototype; - * App.prototype.set = function() {}; - * App.prototype.get = function() {}; - * - * var obj = {}; - * copy(obj, proto); - * ``` - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public + * Expose `Cache.namespace` */ -function copy(receiver, provider, omit) { - if (!isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } +module.exports.namespace = namespace; - var props = nativeKeys(provider); - var keys = Object.keys(provider); - var len = props.length; - omit = arrayify(omit); - while (len--) { - var key = props[len]; +/***/ }), +/* 428 */ +/***/ (function(module, exports, __webpack_require__) { - if (has(keys, key)) { - define(receiver, key, provider[key]); - } else if (!(key in receiver) && !has(omit, key)) { - copyDescriptor(receiver, provider, key); - } - } -}; + +/** + * Expose `Emitter`. + */ + +if (true) { + module.exports = Emitter; +} + +/** + * Initialize a new `Emitter`. + * + * @api public + */ + +function Emitter(obj) { + if (obj) return mixin(obj); +}; + +/** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; +} + +/** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.on = +Emitter.prototype.addEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks['$' + event] = this._callbacks['$' + event] || []) + .push(fn); + return this; +}; + +/** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.once = function(event, fn){ + function on() { + this.off(event, on); + fn.apply(this, arguments); + } + + on.fn = fn; + this.on(event, on); + return this; +}; + +/** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.off = +Emitter.prototype.removeListener = +Emitter.prototype.removeAllListeners = +Emitter.prototype.removeEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks['$' + event]; + if (!callbacks) return this; + + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks['$' + event]; + return this; + } + + // remove specific handler + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; + } + } + return this; +}; + +/** + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} + */ + +Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks['$' + event]; + + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); + } + } + + return this; +}; + +/** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + +Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks['$' + event] || []; +}; + +/** + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public + */ + +Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; +}; -/** - * Return true if the given value is an object or function - */ -function isObject(val) { - return typeOf(val) === 'object' || typeof val === 'function'; -} +/***/ }), +/* 429 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Returns true if an array has any of the given elements, or an - * object has any of the give keys. - * - * ```js - * has(['a', 'b', 'c'], 'c'); - * //=> true - * - * has(['a', 'b', 'c'], ['c', 'z']); - * //=> true +"use strict"; +/*! + * collection-visit * - * has({a: 'b', c: 'd'}, ['c', 'z']); - * //=> true - * ``` - * @param {Object} `obj` - * @param {String|Array} `val` - * @return {Boolean} + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -function has(obj, val) { - val = arrayify(val); - var len = val.length; - if (isObject(obj)) { - for (var key in obj) { - if (val.indexOf(key) > -1) { - return true; - } - } - var keys = nativeKeys(obj); - return has(keys, val); +var visit = __webpack_require__(430); +var mapVisit = __webpack_require__(431); + +module.exports = function(collection, method, val) { + var result; + + if (typeof val === 'string' && (method in collection)) { + var args = [].slice.call(arguments, 2); + result = collection[method].apply(collection, args); + } else if (Array.isArray(val)) { + result = mapVisit.apply(null, arguments); + } else { + result = visit.apply(null, arguments); } - if (Array.isArray(obj)) { - var arr = obj; - while (len--) { - if (arr.indexOf(val[len]) > -1) { - return true; - } - } - return false; + if (typeof result !== 'undefined') { + return result; } - throw new TypeError('expected an array or object.'); -} + return collection; +}; -/** - * Cast the given value to an array. - * - * ```js - * arrayify('foo'); - * //=> ['foo'] - * - * arrayify(['foo']); - * //=> ['foo'] - * ``` - * - * @param {String|Array} `val` - * @return {Array} - */ -function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -} +/***/ }), +/* 430 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Returns true if a value has a `contructor` - * - * ```js - * hasConstructor({}); - * //=> true +"use strict"; +/*! + * object-visit * - * hasConstructor(Object.create(null)); - * //=> false - * ``` - * @param {Object} `value` - * @return {Boolean} + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -function hasConstructor(val) { - return isObject(val) && typeof val.constructor !== 'undefined'; -} -/** - * Get the native `ownPropertyNames` from the constructor of the - * given `object`. An empty array is returned if the object does - * not have a constructor. - * - * ```js - * nativeKeys({a: 'b', b: 'c', c: 'd'}) - * //=> ['a', 'b', 'c'] - * - * nativeKeys(function(){}) - * //=> ['length', 'caller'] - * ``` - * - * @param {Object} `obj` Object that has a `constructor`. - * @return {Array} Array of keys. - */ -function nativeKeys(val) { - if (!hasConstructor(val)) return []; - return Object.getOwnPropertyNames(val); -} +var isObject = __webpack_require__(404); -/** - * Expose `copy` - */ +module.exports = function visit(thisArg, method, target, val) { + if (!isObject(thisArg) && typeof thisArg !== 'function') { + throw new Error('object-visit expects `thisArg` to be an object.'); + } -module.exports = copy; + if (typeof method !== 'string') { + throw new Error('object-visit expects `method` name to be a string'); + } -/** - * Expose `copy.has` for tests - */ + if (typeof thisArg[method] !== 'function') { + return thisArg; + } -module.exports.has = has; + var args = [].slice.call(arguments, 3); + target = target || {}; + + for (var key in target) { + var arr = [key, target[key]].concat(args); + thisArg[method].apply(thisArg, arr); + } + return thisArg; +}; /***/ }), -/* 464 */ +/* 431 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * copy-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ +var util = __webpack_require__(29); +var visit = __webpack_require__(430); /** - * Copy a descriptor from one object to another. - * - * ```js - * function App() { - * this.cache = {}; - * } - * App.prototype.set = function(key, val) { - * this.cache[key] = val; - * return this; - * }; - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this.cache).length; - * } - * }); - * - * copy(App.prototype, 'count', 'len'); - * - * // create an instance - * var app = new App(); - * - * app.set('a', true); - * app.set('b', true); - * app.set('c', true); + * Map `visit` over an array of objects. * - * console.log(app.count); - * //=> 3 - * console.log(app.len); - * //=> 3 - * ``` - * @name copy - * @param {Object} `receiver` The target object - * @param {Object} `provider` The provider object - * @param {String} `from` The key to copy on provider. - * @param {String} `to` Optionally specify a new key name to use. - * @return {Object} - * @api public + * @param {Object} `collection` The context in which to invoke `method` + * @param {String} `method` Name of the method to call on `collection` + * @param {Object} `arr` Array of objects. */ -module.exports = function copyDescriptor(receiver, provider, from, to) { - if (!isObject(provider) && typeof provider !== 'function') { - to = from; - from = provider; - provider = receiver; - } - if (!isObject(receiver) && typeof receiver !== 'function') { - throw new TypeError('expected the first argument to be an object'); - } - if (!isObject(provider) && typeof provider !== 'function') { - throw new TypeError('expected provider to be an object'); +module.exports = function mapVisit(collection, method, val) { + if (isObject(val)) { + return visit.apply(null, arguments); } - if (typeof to !== 'string') { - to = from; - } - if (typeof from !== 'string') { - throw new TypeError('expected key to be a string'); + if (!Array.isArray(val)) { + throw new TypeError('expected an array: ' + util.inspect(val)); } - if (!(from in provider)) { - throw new Error('property "' + from + '" does not exist'); - } + var args = [].slice.call(arguments, 3); - var val = Object.getOwnPropertyDescriptor(provider, from); - if (val) Object.defineProperty(receiver, to, val); + for (var i = 0; i < val.length; i++) { + var ele = val[i]; + if (isObject(ele)) { + visit.apply(null, [collection, method, ele].concat(args)); + } else { + collection[method].apply(collection, [ele].concat(args)); + } + } }; function isObject(val) { - return {}.toString.call(val) === '[object Object]'; + return val && (typeof val === 'function' || (!Array.isArray(val) && typeof val === 'object')); } - /***/ }), -/* 465 */ +/* 432 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * define-property + * to-object-path * * Copyright (c) 2015, Jon Schlinkert. * Licensed under the MIT License. @@ -43223,421 +40756,466 @@ function isObject(val) { -var isDescriptor = __webpack_require__(466); +var typeOf = __webpack_require__(409); -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); +module.exports = function toPath(args) { + if (typeOf(args) !== 'arguments') { + args = arguments; } + return filter(args).join('.'); +}; - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } +function filter(arr) { + var len = arr.length; + var idx = -1; + var res = []; - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); + while (++idx < len) { + var ele = arr[idx]; + if (typeOf(ele) === 'arguments' || Array.isArray(ele)) { + res.push.apply(res, filter(ele)); + } else if (typeof ele === 'string') { + res.push(ele); + } } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; + return res; +} /***/ }), -/* 466 */ +/* 433 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ +var isObject = __webpack_require__(395); +var union = __webpack_require__(434); +var get = __webpack_require__(435); +var set = __webpack_require__(436); -var typeOf = __webpack_require__(467); -var isAccessor = __webpack_require__(468); -var isData = __webpack_require__(469); - -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; +module.exports = function unionValue(obj, prop, value) { + if (!isObject(obj)) { + throw new TypeError('union-value expects the first argument to be an object.'); } - if ('get' in obj) { - return isAccessor(obj, key); + + if (typeof prop !== 'string') { + throw new TypeError('union-value expects `prop` to be a string.'); } - return isData(obj, key); + + var arr = arrayify(get(obj, prop)); + set(obj, prop, union(arr, arrayify(value))); + return obj; }; +function arrayify(val) { + if (val === null || typeof val === 'undefined') { + return []; + } + if (Array.isArray(val)) { + return val; + } + return [val]; +} -/***/ }), -/* 467 */ -/***/ (function(module, exports) { -var toString = Object.prototype.toString; +/***/ }), +/* 434 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ +"use strict"; -module.exports = function kindOf(val) { - var type = typeof val; - // primitivies - if (type === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (type === 'string' || val instanceof String) { - return 'string'; - } - if (type === 'number' || val instanceof Number) { - return 'number'; +module.exports = function union(init) { + if (!Array.isArray(init)) { + throw new TypeError('arr-union expects the first argument to be an array.'); } - // functions - if (type === 'function' || val instanceof Function) { - if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { - return 'generatorfunction'; + var len = arguments.length; + var i = 0; + + while (++i < len) { + var arg = arguments[i]; + if (!arg) continue; + + if (!Array.isArray(arg)) { + arg = [arg]; } - return 'function'; - } - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } + for (var j = 0; j < arg.length; j++) { + var ele = arg[j]; - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; + if (init.indexOf(ele) >= 0) { + continue; + } + init.push(ele); + } } + return init; +}; - // other objects - type = toString.call(val); - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; - } +/***/ }), +/* 435 */ +/***/ (function(module, exports) { - // buffer - if (isBuffer(val)) { - return 'buffer'; - } +/*! + * get-value + * + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. + */ - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - if (type === '[object Map Iterator]') { - return 'mapiterator'; - } - if (type === '[object Set Iterator]') { - return 'setiterator'; - } - if (type === '[object String Iterator]') { - return 'stringiterator'; - } - if (type === '[object Array Iterator]') { - return 'arrayiterator'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; +module.exports = function(obj, prop, a, b, c) { + if (!isObject(obj) || !prop) { + return obj; } - if (type === '[object Float64Array]') { - return 'float64array'; + + prop = toString(prop); + + // allowing for multiple properties to be passed as + // a string or array, but much faster (3-4x) than doing + // `[].slice.call(arguments)` + if (a) prop += '.' + toString(a); + if (b) prop += '.' + toString(b); + if (c) prop += '.' + toString(c); + + if (prop in obj) { + return obj[prop]; } - // must be a plain object - return 'object'; + var segs = prop.split('.'); + var len = segs.length; + var i = -1; + + while (obj && (++i < len)) { + var key = segs[i]; + while (key[key.length - 1] === '\\') { + key = key.slice(0, -1) + '.' + segs[++i]; + } + obj = obj[key]; + } + return obj; }; -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ +function isObject(val) { + return val !== null && (typeof val === 'object' || typeof val === 'function'); +} -function isBuffer(val) { - return val.constructor - && typeof val.constructor.isBuffer === 'function' - && val.constructor.isBuffer(val); +function toString(val) { + if (!val) return ''; + if (Array.isArray(val)) { + return val.join('.'); + } + return val; } /***/ }), -/* 468 */ +/* 436 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-accessor-descriptor + * set-value * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -var typeOf = __webpack_require__(420); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; +var toPath = __webpack_require__(432); +var extend = __webpack_require__(394); +var isPlainObject = __webpack_require__(403); +var isObject = __webpack_require__(395); -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; +module.exports = function(obj, path, val) { + if (!isObject(obj)) { + return obj; } - if (typeOf(obj) !== 'object') { - return false; + if (Array.isArray(path)) { + path = toPath(path); } - if (has(obj, 'value') || has(obj, 'writable')) { - return false; + if (typeof path !== 'string') { + return obj; } - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } + var segs = path.split('.'); + var len = segs.length, i = -1; + var res = obj; + var last; - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } + while (++i < len) { + var key = segs[i]; - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; + while (key[key.length - 1] === '\\') { + key = key.slice(0, -1) + '.' + segs[++i]; } - if (typeOf(obj[key]) === accessor[key]) { - continue; + if (i === len - 1) { + last = key; + break; } - if (typeof obj[key] !== 'undefined') { - return false; + if (!isObject(obj[key])) { + obj[key] = {}; + } + obj = obj[key]; + } + + if (obj.hasOwnProperty(last) && isObject(obj[last])) { + if (isPlainObject(val)) { + extend(obj[last], val); + } else { + obj[last] = val; + } + + } else { + obj[last] = val; + } + return res; +}; + + + +/***/ }), +/* 437 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * unset-value + * + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. + */ + + + +var isObject = __webpack_require__(404); +var has = __webpack_require__(438); + +module.exports = function unset(obj, prop) { + if (!isObject(obj)) { + throw new TypeError('expected an object.'); + } + if (obj.hasOwnProperty(prop)) { + delete obj[prop]; + return true; + } + + if (has(obj, prop)) { + var segs = prop.split('.'); + var last = segs.pop(); + while (segs.length && segs[segs.length - 1].slice(-1) === '\\') { + last = segs.pop().slice(0, -1) + '.' + last; } + while (segs.length) obj = obj[prop = segs.shift()]; + return (delete obj[last]); } return true; -} +}; -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} -/** - * Expose `isAccessorDescriptor` +/***/ }), +/* 438 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * has-value + * + * Copyright (c) 2014-2016, Jon Schlinkert. + * Licensed under the MIT License. */ -module.exports = isAccessorDescriptor; + + +var isObject = __webpack_require__(439); +var hasValues = __webpack_require__(441); +var get = __webpack_require__(435); + +module.exports = function(obj, prop, noZero) { + if (isObject(obj)) { + return hasValues(get(obj, prop), noZero); + } + return hasValues(obj, prop); +}; /***/ }), -/* 469 */ +/* 439 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-data-descriptor + * isobject * - * Copyright (c) 2015, Jon Schlinkert. + * Copyright (c) 2014-2015, Jon Schlinkert. * Licensed under the MIT License. */ -var typeOf = __webpack_require__(420); +var isArray = __webpack_require__(440); -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' +module.exports = function isObject(val) { + return val != null && typeof val === 'object' && isArray(val) === false; }; -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; - } - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } +/***/ }), +/* 440 */ +/***/ (function(module, exports) { - if (!('value' in obj) && !('writable' in obj)) { - return false; - } +var toString = {}.toString; - for (var key in obj) { - if (key === 'value') continue; +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; - if (!data.hasOwnProperty(key)) { - continue; - } - if (typeOf(obj[key]) === data[key]) { - continue; - } +/***/ }), +/* 441 */ +/***/ (function(module, exports, __webpack_require__) { - if (typeof obj[key] !== 'undefined') { +"use strict"; +/*! + * has-values + * + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. + */ + + + +module.exports = function hasValue(o, noZero) { + if (o === null || o === undefined) { + return false; + } + + if (typeof o === 'boolean') { + return true; + } + + if (typeof o === 'number') { + if (o === 0 && noZero === true) { return false; } + return true; } - return true; -} -/** - * Expose `isDataDescriptor` - */ + if (o.length !== undefined) { + return o.length !== 0; + } -module.exports = isDataDescriptor; + for (var key in o) { + if (o.hasOwnProperty(key)) { + return true; + } + } + return false; +}; /***/ }), -/* 470 */ +/* 442 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * define-property + * has-value * - * Copyright (c) 2015, Jon Schlinkert. + * Copyright (c) 2014-2017, Jon Schlinkert. * Licensed under the MIT License. */ -var isDescriptor = __webpack_require__(471); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } +var isObject = __webpack_require__(404); +var hasValues = __webpack_require__(443); +var get = __webpack_require__(435); - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); +module.exports = function(val, prop) { + return hasValues(isObject(val) && prop ? get(val, prop) : val); }; /***/ }), -/* 471 */ +/* 443 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-descriptor + * has-values * - * Copyright (c) 2015-2017, Jon Schlinkert. + * Copyright (c) 2014-2015, 2017, Jon Schlinkert. * Released under the MIT License. */ -var typeOf = __webpack_require__(472); -var isAccessor = __webpack_require__(473); -var isData = __webpack_require__(475); +var typeOf = __webpack_require__(444); +var isNumber = __webpack_require__(408); -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; +module.exports = function hasValue(val) { + // is-number checks for NaN and other edge cases + if (isNumber(val)) { + return true; } - if ('get' in obj) { - return isAccessor(obj, key); + + switch (typeOf(val)) { + case 'null': + case 'boolean': + case 'function': + return true; + case 'string': + case 'arguments': + return val.length !== 0; + case 'error': + return val.message !== ''; + case 'array': + var len = val.length; + if (len === 0) { + return false; + } + for (var i = 0; i < len; i++) { + if (hasValue(val[i])) { + return true; + } + } + return false; + case 'file': + case 'map': + case 'set': + return val.size !== 0; + case 'object': + var keys = Object.keys(val); + if (keys.length === 0) { + return false; + } + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (hasValue(val[key])) { + return true; + } + } + return false; + default: { + return false; + } } - return isData(obj, key); }; /***/ }), -/* 472 */ -/***/ (function(module, exports) { +/* 444 */ +/***/ (function(module, exports, __webpack_require__) { +var isBuffer = __webpack_require__(391); var toString = Object.prototype.toString; /** @@ -43648,10 +41226,8 @@ var toString = Object.prototype.toString; */ module.exports = function kindOf(val) { - var type = typeof val; - // primitivies - if (type === 'undefined') { + if (typeof val === 'undefined') { return 'undefined'; } if (val === null) { @@ -43660,18 +41236,15 @@ module.exports = function kindOf(val) { if (val === true || val === false || val instanceof Boolean) { return 'boolean'; } - if (type === 'string' || val instanceof String) { + if (typeof val === 'string' || val instanceof String) { return 'string'; } - if (type === 'number' || val instanceof Number) { + if (typeof val === 'number' || val instanceof Number) { return 'number'; } // functions - if (type === 'function' || val instanceof Function) { - if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { - return 'generatorfunction'; - } + if (typeof val === 'function' || val instanceof Function) { return 'function'; } @@ -43689,7 +41262,7 @@ module.exports = function kindOf(val) { } // other objects - type = toString.call(val); + var type = toString.call(val); if (type === '[object RegExp]') { return 'regexp'; @@ -43728,20 +41301,7 @@ module.exports = function kindOf(val) { if (type === '[object Symbol]') { return 'symbol'; } - - if (type === '[object Map Iterator]') { - return 'mapiterator'; - } - if (type === '[object Set Iterator]') { - return 'setiterator'; - } - if (type === '[object String Iterator]') { - return 'stringiterator'; - } - if (type === '[object Array Iterator]') { - return 'arrayiterator'; - } - + // typed arrays if (type === '[object Int8Array]') { return 'int8array'; @@ -43775,1013 +41335,969 @@ module.exports = function kindOf(val) { return 'object'; }; -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - return val.constructor - && typeof val.constructor.isBuffer === 'function' - && val.constructor.isBuffer(val); -} - /***/ }), -/* 473 */ +/* 445 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-accessor-descriptor + * set-value * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -var typeOf = __webpack_require__(474); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; - -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } +var split = __webpack_require__(400); +var extend = __webpack_require__(394); +var isPlainObject = __webpack_require__(403); +var isObject = __webpack_require__(395); - if (typeOf(obj) !== 'object') { - return false; +module.exports = function(obj, prop, val) { + if (!isObject(obj)) { + return obj; } - if (has(obj, 'value') || has(obj, 'writable')) { - return false; + if (Array.isArray(prop)) { + prop = [].concat.apply([], prop).join('.'); } - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; + if (typeof prop !== 'string') { + return obj; } - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } + var keys = split(prop, {sep: '.', brackets: true}); + var len = keys.length; + var idx = -1; + var current = obj; - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { + while (++idx < len) { + var key = keys[idx]; + if (idx !== len - 1) { + if (!isObject(current[key])) { + current[key] = {}; + } + current = current[key]; continue; } - if (typeOf(obj[key]) === accessor[key]) { - continue; + if (isPlainObject(current[key]) && isPlainObject(val)) { + current[key] = extend({}, current[key], val); + } else { + current[key] = val; } + } - if (typeof obj[key] !== 'undefined') { - return false; + return obj; +}; + + +/***/ }), +/* 446 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isExtendable = __webpack_require__(447); +var forIn = __webpack_require__(448); + +function mixinDeep(target, objects) { + var len = arguments.length, i = 0; + while (++i < len) { + var obj = arguments[i]; + if (isObject(obj)) { + forIn(obj, copy, target); } } - return true; + return target; } -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); +/** + * Copy properties from the source object to the + * target object. + * + * @param {*} `val` + * @param {String} `key` + */ + +function copy(val, key) { + var obj = this[key]; + if (isObject(val) && isObject(obj)) { + mixinDeep(obj, val); + } else { + this[key] = val; + } } /** - * Expose `isAccessorDescriptor` + * Returns true if `val` is an object or function. + * + * @param {any} val + * @return {Boolean} */ -module.exports = isAccessorDescriptor; +function isObject(val) { + return isExtendable(val) && !Array.isArray(val); +} + +/** + * Expose `mixinDeep` + */ + +module.exports = mixinDeep; /***/ }), -/* 474 */ +/* 447 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. +"use strict"; +/*! + * is-extendable * - * @param {*} `val` - * @return {*} Native javascript type + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } +var isPlainObject = __webpack_require__(403); - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } +module.exports = function isExtendable(val) { + return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); +}; - // other objects - var type = toString.call(val); - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } +/***/ }), +/* 448 */ +/***/ (function(module, exports, __webpack_require__) { - // buffer - if (isBuffer(val)) { - return 'buffer'; - } +"use strict"; +/*! + * for-in + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - // must be a plain object - return 'object'; +module.exports = function forIn(obj, fn, thisArg) { + for (var key in obj) { + if (fn.call(thisArg, obj[key], key, obj) === false) { + break; + } + } }; /***/ }), -/* 475 */ -/***/ (function(module, exports, __webpack_require__) { +/* 449 */ +/***/ (function(module, exports) { -"use strict"; /*! - * is-data-descriptor + * pascalcase * * Copyright (c) 2015, Jon Schlinkert. * Licensed under the MIT License. */ +function pascalcase(str) { + if (typeof str !== 'string') { + throw new TypeError('expected a string.'); + } + str = str.replace(/([A-Z])/g, ' $1'); + if (str.length === 1) { return str.toUpperCase(); } + str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); + str = str.charAt(0).toUpperCase() + str.slice(1); + return str.replace(/[\W_]+(\w|$)/g, function (_, ch) { + return ch.toUpperCase(); + }); +} +module.exports = pascalcase; -var typeOf = __webpack_require__(476); -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' +/***/ }), +/* 450 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var util = __webpack_require__(29); +var utils = __webpack_require__(451); + +/** + * Expose class utils + */ + +var cu = module.exports; + +/** + * Expose class utils: `cu` + */ + +cu.isObject = function isObject(val) { + return utils.isObj(val) || typeof val === 'function'; }; -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; - } +/** + * Returns true if an array has any of the given elements, or an + * object has any of the give keys. + * + * ```js + * cu.has(['a', 'b', 'c'], 'c'); + * //=> true + * + * cu.has(['a', 'b', 'c'], ['c', 'z']); + * //=> true + * + * cu.has({a: 'b', c: 'd'}, ['c', 'z']); + * //=> true + * ``` + * @param {Object} `obj` + * @param {String|Array} `val` + * @return {Boolean} + * @api public + */ - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; +cu.has = function has(obj, val) { + val = cu.arrayify(val); + var len = val.length; + + if (cu.isObject(obj)) { + for (var key in obj) { + if (val.indexOf(key) > -1) { + return true; + } + } + + var keys = cu.nativeKeys(obj); + return cu.has(keys, val); } - if (!('value' in obj) && !('writable' in obj)) { + if (Array.isArray(obj)) { + var arr = obj; + while (len--) { + if (arr.indexOf(val[len]) > -1) { + return true; + } + } return false; } - for (var key in obj) { - if (key === 'value') continue; - - if (!data.hasOwnProperty(key)) { - continue; - } + throw new TypeError('expected an array or object.'); +}; - if (typeOf(obj[key]) === data[key]) { - continue; - } +/** + * Returns true if an array or object has all of the given values. + * + * ```js + * cu.hasAll(['a', 'b', 'c'], 'c'); + * //=> true + * + * cu.hasAll(['a', 'b', 'c'], ['c', 'z']); + * //=> false + * + * cu.hasAll({a: 'b', c: 'd'}, ['c', 'z']); + * //=> false + * ``` + * @param {Object|Array} `val` + * @param {String|Array} `values` + * @return {Boolean} + * @api public + */ - if (typeof obj[key] !== 'undefined') { +cu.hasAll = function hasAll(val, values) { + values = cu.arrayify(values); + var len = values.length; + while (len--) { + if (!cu.has(val, values[len])) { return false; } } return true; -} +}; /** - * Expose `isDataDescriptor` + * Cast the given value to an array. + * + * ```js + * cu.arrayify('foo'); + * //=> ['foo'] + * + * cu.arrayify(['foo']); + * //=> ['foo'] + * ``` + * + * @param {String|Array} `val` + * @return {Array} + * @api public */ -module.exports = isDataDescriptor; +cu.arrayify = function arrayify(val) { + return val ? (Array.isArray(val) ? val : [val]) : []; +}; +/** + * Noop + */ -/***/ }), -/* 476 */ -/***/ (function(module, exports, __webpack_require__) { +cu.noop = function noop() { + return; +}; -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; +/** + * Returns the first argument passed to the function. + */ + +cu.identity = function identity(val) { + return val; +}; /** - * Get the native `typeof` a value. + * Returns true if a value has a `contructor` * - * @param {*} `val` - * @return {*} Native javascript type + * ```js + * cu.hasConstructor({}); + * //=> true + * + * cu.hasConstructor(Object.create(null)); + * //=> false + * ``` + * @param {Object} `value` + * @return {Boolean} + * @api public */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } +cu.hasConstructor = function hasConstructor(val) { + return cu.isObject(val) && typeof val.constructor !== 'undefined'; +}; - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } +/** + * Get the native `ownPropertyNames` from the constructor of the + * given `object`. An empty array is returned if the object does + * not have a constructor. + * + * ```js + * cu.nativeKeys({a: 'b', b: 'c', c: 'd'}) + * //=> ['a', 'b', 'c'] + * + * cu.nativeKeys(function(){}) + * //=> ['length', 'caller'] + * ``` + * + * @param {Object} `obj` Object that has a `constructor`. + * @return {Array} Array of keys. + * @api public + */ - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } +cu.nativeKeys = function nativeKeys(val) { + if (!cu.hasConstructor(val)) return []; + return Object.getOwnPropertyNames(val); +}; - // other objects - var type = toString.call(val); +/** + * Returns property descriptor `key` if it's an "own" property + * of the given object. + * + * ```js + * function App() {} + * Object.defineProperty(App.prototype, 'count', { + * get: function() { + * return Object.keys(this).length; + * } + * }); + * cu.getDescriptor(App.prototype, 'count'); + * // returns: + * // { + * // get: [Function], + * // set: undefined, + * // enumerable: false, + * // configurable: false + * // } + * ``` + * + * @param {Object} `obj` + * @param {String} `key` + * @return {Object} Returns descriptor `key` + * @api public + */ - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; +cu.getDescriptor = function getDescriptor(obj, key) { + if (!cu.isObject(obj)) { + throw new TypeError('expected an object.'); } - - // buffer - if (isBuffer(val)) { - return 'buffer'; + if (typeof key !== 'string') { + throw new TypeError('expected key to be a string.'); } + return Object.getOwnPropertyDescriptor(obj, key); +}; - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } +/** + * Copy a descriptor from one object to another. + * + * ```js + * function App() {} + * Object.defineProperty(App.prototype, 'count', { + * get: function() { + * return Object.keys(this).length; + * } + * }); + * var obj = {}; + * cu.copyDescriptor(obj, App.prototype, 'count'); + * ``` + * @param {Object} `receiver` + * @param {Object} `provider` + * @param {String} `name` + * @return {Object} + * @api public + */ - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; +cu.copyDescriptor = function copyDescriptor(receiver, provider, name) { + if (!cu.isObject(receiver)) { + throw new TypeError('expected receiving object to be an object.'); } - if (type === '[object Float32Array]') { - return 'float32array'; + if (!cu.isObject(provider)) { + throw new TypeError('expected providing object to be an object.'); } - if (type === '[object Float64Array]') { - return 'float64array'; + if (typeof name !== 'string') { + throw new TypeError('expected name to be a string.'); } - // must be a plain object - return 'object'; + var val = cu.getDescriptor(provider, name); + if (val) Object.defineProperty(receiver, name, val); }; - -/***/ }), -/* 477 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property +/** + * Copy static properties, prototype properties, and descriptors + * from one object to another. * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * @param {Object} `receiver` + * @param {Object} `provider` + * @param {String|Array} `omit` One or more properties to omit + * @return {Object} + * @api public */ - - -var isDescriptor = __webpack_require__(478); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); +cu.copy = function copy(receiver, provider, omit) { + if (!cu.isObject(receiver)) { + throw new TypeError('expected receiving object to be an object.'); } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); + if (!cu.isObject(provider)) { + throw new TypeError('expected providing object to be an object.'); } + var props = Object.getOwnPropertyNames(provider); + var keys = Object.keys(provider); + var len = props.length, + key; + omit = cu.arrayify(omit); - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } + while (len--) { + key = props[len]; - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); + if (cu.has(keys, key)) { + utils.define(receiver, key, provider[key]); + } else if (!(key in receiver) && !cu.has(omit, key)) { + cu.copyDescriptor(receiver, provider, key); + } + } }; - -/***/ }), -/* 478 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-descriptor +/** + * Inherit the static properties, prototype properties, and descriptors + * from of an object. * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * @param {Object} `receiver` + * @param {Object} `provider` + * @param {String|Array} `omit` One or more properties to omit + * @return {Object} + * @api public */ - - -var typeOf = __webpack_require__(479); -var isAccessor = __webpack_require__(480); -var isData = __webpack_require__(482); - -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; +cu.inherit = function inherit(receiver, provider, omit) { + if (!cu.isObject(receiver)) { + throw new TypeError('expected receiving object to be an object.'); } - if ('get' in obj) { - return isAccessor(obj, key); + if (!cu.isObject(provider)) { + throw new TypeError('expected providing object to be an object.'); } - return isData(obj, key); -}; + var keys = []; + for (var key in provider) { + keys.push(key); + receiver[key] = provider[key]; + } -/***/ }), -/* 479 */ -/***/ (function(module, exports) { + keys = keys.concat(cu.arrayify(omit)); -var toString = Object.prototype.toString; + var a = provider.prototype || provider; + var b = receiver.prototype || receiver; + cu.copy(b, a, keys); +}; /** - * Get the native `typeof` a value. + * Returns a function for extending the static properties, + * prototype properties, and descriptors from the `Parent` + * constructor onto `Child` constructors. * - * @param {*} `val` - * @return {*} Native javascript type + * ```js + * var extend = cu.extend(Parent); + * Parent.extend(Child); + * + * // optional methods + * Parent.extend(Child, { + * foo: function() {}, + * bar: function() {} + * }); + * ``` + * @param {Function} `Parent` Parent ctor + * @param {Function} `extend` Optional extend function to handle custom extensions. Useful when updating methods that require a specific prototype. + * @param {Function} `Child` Child ctor + * @param {Object} `proto` Optionally pass additional prototype properties to inherit. + * @return {Object} + * @api public */ -module.exports = function kindOf(val) { - var type = typeof val; +cu.extend = function() { + // keep it lazy, instead of assigning to `cu.extend` + return utils.staticExtend.apply(null, arguments); +}; - // primitivies - if (type === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (type === 'string' || val instanceof String) { - return 'string'; - } - if (type === 'number' || val instanceof Number) { - return 'number'; - } +/** + * Bubble up events emitted from static methods on the Parent ctor. + * + * @param {Object} `Parent` + * @param {Array} `events` Event names to bubble up + * @api public + */ - // functions - if (type === 'function' || val instanceof Function) { - if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { - return 'generatorfunction'; +cu.bubble = function(Parent, events) { + events = events || []; + Parent.bubble = function(Child, arr) { + if (Array.isArray(arr)) { + events = utils.union([], events, arr); } - return 'function'; - } + var len = events.length; + var idx = -1; + while (++idx < len) { + var name = events[idx]; + Parent.on(name, Child.emit.bind(Child, name)); + } + cu.bubble(Child, events); + }; +}; - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } +/***/ }), +/* 451 */ +/***/ (function(module, exports, __webpack_require__) { - // other objects - type = toString.call(val); +"use strict"; - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; - } - // buffer - if (isBuffer(val)) { - return 'buffer'; - } +var utils = {}; - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - if (type === '[object Map Iterator]') { - return 'mapiterator'; - } - if (type === '[object Set Iterator]') { - return 'setiterator'; - } - if (type === '[object String Iterator]') { - return 'stringiterator'; - } - if (type === '[object Array Iterator]') { - return 'arrayiterator'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - // must be a plain object - return 'object'; -}; /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * Lazily required module dependencies + */ + +utils.union = __webpack_require__(434); +utils.define = __webpack_require__(386); +utils.isObj = __webpack_require__(404); +utils.staticExtend = __webpack_require__(452); + + +/** + * Expose `utils` */ -function isBuffer(val) { - return val.constructor - && typeof val.constructor.isBuffer === 'function' - && val.constructor.isBuffer(val); -} +module.exports = utils; /***/ }), -/* 480 */ +/* 452 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-accessor-descriptor + * static-extend * - * Copyright (c) 2015, Jon Schlinkert. + * Copyright (c) 2016, Jon Schlinkert. * Licensed under the MIT License. */ -var typeOf = __webpack_require__(481); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; +var copy = __webpack_require__(453); +var define = __webpack_require__(386); +var util = __webpack_require__(29); -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } +/** + * Returns a function for extending the static properties, + * prototype properties, and descriptors from the `Parent` + * constructor onto `Child` constructors. + * + * ```js + * var extend = require('static-extend'); + * Parent.extend = extend(Parent); + * + * // optionally pass a custom merge function as the second arg + * Parent.extend = extend(Parent, function(Child) { + * Child.prototype.mixin = function(key, val) { + * Child.prototype[key] = val; + * }; + * }); + * + * // extend "child" constructors + * Parent.extend(Child); + * + * // optionally define prototype methods as the second arg + * Parent.extend(Child, { + * foo: function() {}, + * bar: function() {} + * }); + * ``` + * @param {Function} `Parent` Parent ctor + * @param {Function} `extendFn` Optional extend function for handling any necessary custom merging. Useful when updating methods that require a specific prototype. + * @param {Function} `Child` Child ctor + * @param {Object} `proto` Optionally pass additional prototype properties to inherit. + * @return {Object} + * @api public + */ - if (typeOf(obj) !== 'object') { - return false; +function extend(Parent, extendFn) { + if (typeof Parent !== 'function') { + throw new TypeError('expected Parent to be a function.'); } - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } + return function(Ctor, proto) { + if (typeof Ctor !== 'function') { + throw new TypeError('expected Ctor to be a function.'); + } - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } + util.inherits(Ctor, Parent); + copy(Ctor, Parent); - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } + // proto can be null or a plain object + if (typeof proto === 'object') { + var obj = Object.create(proto); - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; + for (var k in obj) { + Ctor.prototype[k] = obj[k]; + } } - if (typeOf(obj[key]) === accessor[key]) { - continue; - } + // keep a reference to the parent prototype + define(Ctor.prototype, '_parent_', { + configurable: true, + set: function() {}, + get: function() { + return Parent.prototype; + } + }); - if (typeof obj[key] !== 'undefined') { - return false; + if (typeof extendFn === 'function') { + extendFn(Ctor, Parent); } - } - return true; -} -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} + Ctor.extend = extend(Ctor, extendFn); + }; +}; /** - * Expose `isAccessorDescriptor` + * Expose `extend` */ -module.exports = isAccessorDescriptor; +module.exports = extend; /***/ }), -/* 481 */ +/* 453 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; +"use strict"; + + +var typeOf = __webpack_require__(409); +var copyDescriptor = __webpack_require__(454); +var define = __webpack_require__(386); /** - * Get the native `typeof` a value. + * Copy static properties, prototype properties, and descriptors from one object to another. * - * @param {*} `val` - * @return {*} Native javascript type + * ```js + * function App() {} + * var proto = App.prototype; + * App.prototype.set = function() {}; + * App.prototype.get = function() {}; + * + * var obj = {}; + * copy(obj, proto); + * ``` + * @param {Object} `receiver` + * @param {Object} `provider` + * @param {String|Array} `omit` One or more properties to omit + * @return {Object} + * @api public */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - var type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; +function copy(receiver, provider, omit) { + if (!isObject(receiver)) { + throw new TypeError('expected receiving object to be an object.'); } - if (type === '[object Error]') { - return 'error'; + if (!isObject(provider)) { + throw new TypeError('expected providing object to be an object.'); } - // buffer - if (isBuffer(val)) { - return 'buffer'; - } + var props = nativeKeys(provider); + var keys = Object.keys(provider); + var len = props.length; + omit = arrayify(omit); - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } + while (len--) { + var key = props[len]; - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; + if (has(keys, key)) { + define(receiver, key, provider[key]); + } else if (!(key in receiver) && !has(omit, key)) { + copyDescriptor(receiver, provider, key); + } } - - // must be a plain object - return 'object'; }; +/** + * Return true if the given value is an object or function + */ -/***/ }), -/* 482 */ -/***/ (function(module, exports, __webpack_require__) { +function isObject(val) { + return typeOf(val) === 'object' || typeof val === 'function'; +} -"use strict"; -/*! - * is-data-descriptor +/** + * Returns true if an array has any of the given elements, or an + * object has any of the give keys. * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * ```js + * has(['a', 'b', 'c'], 'c'); + * //=> true + * + * has(['a', 'b', 'c'], ['c', 'z']); + * //=> true + * + * has({a: 'b', c: 'd'}, ['c', 'z']); + * //=> true + * ``` + * @param {Object} `obj` + * @param {String|Array} `val` + * @return {Boolean} */ +function has(obj, val) { + val = arrayify(val); + var len = val.length; + if (isObject(obj)) { + for (var key in obj) { + if (val.indexOf(key) > -1) { + return true; + } + } -var typeOf = __webpack_require__(483); - -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' -}; - -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; - } - - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; + var keys = nativeKeys(obj); + return has(keys, val); } - if (!('value' in obj) && !('writable' in obj)) { + if (Array.isArray(obj)) { + var arr = obj; + while (len--) { + if (arr.indexOf(val[len]) > -1) { + return true; + } + } return false; } - for (var key in obj) { - if (key === 'value') continue; - - if (!data.hasOwnProperty(key)) { - continue; - } + throw new TypeError('expected an array or object.'); +} - if (typeOf(obj[key]) === data[key]) { - continue; - } +/** + * Cast the given value to an array. + * + * ```js + * arrayify('foo'); + * //=> ['foo'] + * + * arrayify(['foo']); + * //=> ['foo'] + * ``` + * + * @param {String|Array} `val` + * @return {Array} + */ - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; +function arrayify(val) { + return val ? (Array.isArray(val) ? val : [val]) : []; } /** - * Expose `isDataDescriptor` + * Returns true if a value has a `contructor` + * + * ```js + * hasConstructor({}); + * //=> true + * + * hasConstructor(Object.create(null)); + * //=> false + * ``` + * @param {Object} `value` + * @return {Boolean} */ -module.exports = isDataDescriptor; - +function hasConstructor(val) { + return isObject(val) && typeof val.constructor !== 'undefined'; +} -/***/ }), -/* 483 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * Get the native `ownPropertyNames` from the constructor of the + * given `object`. An empty array is returned if the object does + * not have a constructor. + * + * ```js + * nativeKeys({a: 'b', b: 'c', c: 'd'}) + * //=> ['a', 'b', 'c'] + * + * nativeKeys(function(){}) + * //=> ['length', 'caller'] + * ``` + * + * @param {Object} `obj` Object that has a `constructor`. + * @return {Array} Array of keys. + */ -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; +function nativeKeys(val) { + if (!hasConstructor(val)) return []; + return Object.getOwnPropertyNames(val); +} /** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type + * Expose `copy` */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } +module.exports = copy; - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } +/** + * Expose `copy.has` for tests + */ - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } +module.exports.has = has; - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - // other objects - var type = toString.call(val); +/***/ }), +/* 454 */ +/***/ (function(module, exports, __webpack_require__) { - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } +"use strict"; +/*! + * copy-descriptor + * + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. + */ - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; +/** + * Copy a descriptor from one object to another. + * + * ```js + * function App() { + * this.cache = {}; + * } + * App.prototype.set = function(key, val) { + * this.cache[key] = val; + * return this; + * }; + * Object.defineProperty(App.prototype, 'count', { + * get: function() { + * return Object.keys(this.cache).length; + * } + * }); + * + * copy(App.prototype, 'count', 'len'); + * + * // create an instance + * var app = new App(); + * + * app.set('a', true); + * app.set('b', true); + * app.set('c', true); + * + * console.log(app.count); + * //=> 3 + * console.log(app.len); + * //=> 3 + * ``` + * @name copy + * @param {Object} `receiver` The target object + * @param {Object} `provider` The provider object + * @param {String} `from` The key to copy on provider. + * @param {String} `to` Optionally specify a new key name to use. + * @return {Object} + * @api public + */ + +module.exports = function copyDescriptor(receiver, provider, from, to) { + if (!isObject(provider) && typeof provider !== 'function') { + to = from; + from = provider; + provider = receiver; } - if (type === '[object Uint16Array]') { - return 'uint16array'; + if (!isObject(receiver) && typeof receiver !== 'function') { + throw new TypeError('expected the first argument to be an object'); } - if (type === '[object Int32Array]') { - return 'int32array'; + if (!isObject(provider) && typeof provider !== 'function') { + throw new TypeError('expected provider to be an object'); } - if (type === '[object Uint32Array]') { - return 'uint32array'; + + if (typeof to !== 'string') { + to = from; } - if (type === '[object Float32Array]') { - return 'float32array'; + if (typeof from !== 'string') { + throw new TypeError('expected key to be a string'); } - if (type === '[object Float64Array]') { - return 'float64array'; + + if (!(from in provider)) { + throw new Error('property "' + from + '" does not exist'); } - // must be a plain object - return 'object'; + var val = Object.getOwnPropertyDescriptor(provider, from); + if (val) Object.defineProperty(receiver, to, val); }; +function isObject(val) { + return {}.toString.call(val) === '[object Object]'; +} + + /***/ }), -/* 484 */ +/* 455 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(485); -var define = __webpack_require__(477); -var debug = __webpack_require__(494)('snapdragon:compiler'); -var utils = __webpack_require__(501); +var use = __webpack_require__(456); +var define = __webpack_require__(386); +var debug = __webpack_require__(458)('snapdragon:compiler'); +var utils = __webpack_require__(465); /** * Create a new `Compiler` with the given `options`. @@ -44924,799 +42440,197 @@ Compiler.prototype = { }, /** - * Compile `ast`. - */ - - compile: function(ast, options) { - var opts = utils.extend({}, this.options, options); - this.ast = ast; - this.parsingErrors = this.ast.errors; - this.output = ''; - - // source map support - if (opts.sourcemap) { - var sourcemaps = __webpack_require__(520); - sourcemaps(this); - this.mapVisit(this.ast.nodes); - this.applySourceMaps(); - this.map = opts.sourcemap === 'generator' ? this.map : this.map.toJSON(); - return this; - } - - this.mapVisit(this.ast.nodes); - return this; - } -}; - -/** - * Expose `Compiler` - */ - -module.exports = Compiler; - - -/***/ }), -/* 485 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * use - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var utils = __webpack_require__(486); - -module.exports = function base(app, opts) { - if (!utils.isObject(app) && typeof app !== 'function') { - throw new TypeError('use: expect `app` be an object or function'); - } - - if (!utils.isObject(opts)) { - opts = {}; - } - - var prop = utils.isString(opts.prop) ? opts.prop : 'fns'; - if (!Array.isArray(app[prop])) { - utils.define(app, prop, []); - } - - /** - * Define a plugin function to be passed to use. The only - * parameter exposed to the plugin is `app`, the object or function. - * passed to `use(app)`. `app` is also exposed as `this` in plugins. - * - * Additionally, **if a plugin returns a function, the function will - * be pushed onto the `fns` array**, allowing the plugin to be - * called at a later point by the `run` method. - * - * ```js - * var use = require('use'); - * - * // define a plugin - * function foo(app) { - * // do stuff - * } - * - * var app = function(){}; - * use(app); - * - * // register plugins - * app.use(foo); - * app.use(bar); - * app.use(baz); - * ``` - * @name .use - * @param {Function} `fn` plugin function to call - * @api public - */ - - utils.define(app, 'use', use); - - /** - * Run all plugins on `fns`. Any plugin that returns a function - * when called by `use` is pushed onto the `fns` array. - * - * ```js - * var config = {}; - * app.run(config); - * ``` - * @name .run - * @param {Object} `value` Object to be modified by plugins. - * @return {Object} Returns the object passed to `run` - * @api public - */ - - utils.define(app, 'run', function(val) { - if (!utils.isObject(val)) return; - decorate(val); - - var self = this || app; - var fns = self[prop]; - var len = fns.length; - var idx = -1; - - while (++idx < len) { - val.use(fns[idx]); - } - return val; - }); - - /** - * Call plugin `fn`. If a function is returned push it into the - * `fns` array to be called by the `run` method. - */ - - function use(fn, options) { - if (typeof fn !== 'function') { - throw new TypeError('.use expects `fn` be a function'); - } - - var self = this || app; - if (typeof opts.fn === 'function') { - opts.fn.call(self, self, options); - } - - var plugin = fn.call(self, self); - if (typeof plugin === 'function') { - var fns = self[prop]; - fns.push(plugin); - } - return self; - } - - /** - * Ensure the `.use` method exists on `val` - */ - - function decorate(val) { - if (!val.use || !val.run) { - base(val); - } - } - - return app; -}; - - -/***/ }), -/* 486 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = {}; - - - -/** - * Lazily required module dependencies - */ - -utils.define = __webpack_require__(487); -utils.isObject = __webpack_require__(415); - - -utils.isString = function(val) { - return val && typeof val === 'string'; -}; - -/** - * Expose `utils` modules - */ - -module.exports = utils; - - -/***/ }), -/* 487 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(488); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 488 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(489); -var isAccessor = __webpack_require__(490); -var isData = __webpack_require__(492); - -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; - - -/***/ }), -/* 489 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ - -module.exports = function kindOf(val) { - var type = typeof val; - - // primitivies - if (type === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (type === 'string' || val instanceof String) { - return 'string'; - } - if (type === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (type === 'function' || val instanceof Function) { - if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { - return 'generatorfunction'; - } - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; - } - - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - if (type === '[object Map Iterator]') { - return 'mapiterator'; - } - if (type === '[object Set Iterator]') { - return 'setiterator'; - } - if (type === '[object String Iterator]') { - return 'stringiterator'; - } - if (type === '[object Array Iterator]') { - return 'arrayiterator'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - - // must be a plain object - return 'object'; -}; - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - return val.constructor - && typeof val.constructor.isBuffer === 'function' - && val.constructor.isBuffer(val); -} - - -/***/ }), -/* 490 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(491); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; - -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (typeOf(obj) !== 'object') { - return false; - } - - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } - - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } - - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } - - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } + * Compile `ast`. + */ - if (typeOf(obj[key]) === accessor[key]) { - continue; - } + compile: function(ast, options) { + var opts = utils.extend({}, this.options, options); + this.ast = ast; + this.parsingErrors = this.ast.errors; + this.output = ''; - if (typeof obj[key] !== 'undefined') { - return false; + // source map support + if (opts.sourcemap) { + var sourcemaps = __webpack_require__(484); + sourcemaps(this); + this.mapVisit(this.ast.nodes); + this.applySourceMaps(); + this.map = opts.sourcemap === 'generator' ? this.map : this.map.toJSON(); + return this; } - } - return true; -} -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} + this.mapVisit(this.ast.nodes); + return this; + } +}; /** - * Expose `isAccessorDescriptor` + * Expose `Compiler` */ -module.exports = isAccessorDescriptor; +module.exports = Compiler; /***/ }), -/* 491 */ +/* 456 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. +"use strict"; +/*! + * use * - * @param {*} `val` - * @return {*} Native javascript type + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - // other objects - var type = toString.call(val); - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } +var utils = __webpack_require__(457); - // buffer - if (isBuffer(val)) { - return 'buffer'; +module.exports = function base(app, opts) { + if (!utils.isObject(app) && typeof app !== 'function') { + throw new TypeError('use: expect `app` be an object or function'); } - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; + if (!utils.isObject(opts)) { + opts = {}; } - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; + var prop = utils.isString(opts.prop) ? opts.prop : 'fns'; + if (!Array.isArray(app[prop])) { + utils.define(app, prop, []); } - // must be a plain object - return 'object'; -}; - - -/***/ }), -/* 492 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-data-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - + /** + * Define a plugin function to be passed to use. The only + * parameter exposed to the plugin is `app`, the object or function. + * passed to `use(app)`. `app` is also exposed as `this` in plugins. + * + * Additionally, **if a plugin returns a function, the function will + * be pushed onto the `fns` array**, allowing the plugin to be + * called at a later point by the `run` method. + * + * ```js + * var use = require('use'); + * + * // define a plugin + * function foo(app) { + * // do stuff + * } + * + * var app = function(){}; + * use(app); + * + * // register plugins + * app.use(foo); + * app.use(bar); + * app.use(baz); + * ``` + * @name .use + * @param {Function} `fn` plugin function to call + * @api public + */ -var typeOf = __webpack_require__(493); + utils.define(app, 'use', use); -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' -}; + /** + * Run all plugins on `fns`. Any plugin that returns a function + * when called by `use` is pushed onto the `fns` array. + * + * ```js + * var config = {}; + * app.run(config); + * ``` + * @name .run + * @param {Object} `value` Object to be modified by plugins. + * @return {Object} Returns the object passed to `run` + * @api public + */ -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; - } + utils.define(app, 'run', function(val) { + if (!utils.isObject(val)) return; + decorate(val); - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } + var self = this || app; + var fns = self[prop]; + var len = fns.length; + var idx = -1; - if (!('value' in obj) && !('writable' in obj)) { - return false; - } + while (++idx < len) { + val.use(fns[idx]); + } + return val; + }); - for (var key in obj) { - if (key === 'value') continue; + /** + * Call plugin `fn`. If a function is returned push it into the + * `fns` array to be called by the `run` method. + */ - if (!data.hasOwnProperty(key)) { - continue; + function use(fn, options) { + if (typeof fn !== 'function') { + throw new TypeError('.use expects `fn` be a function'); } - if (typeOf(obj[key]) === data[key]) { - continue; + var self = this || app; + if (typeof opts.fn === 'function') { + opts.fn.call(self, self, options); } - if (typeof obj[key] !== 'undefined') { - return false; + var plugin = fn.call(self, self); + if (typeof plugin === 'function') { + var fns = self[prop]; + fns.push(plugin); } + return self; } - return true; -} -/** - * Expose `isDataDescriptor` - */ + /** + * Ensure the `.use` method exists on `val` + */ -module.exports = isDataDescriptor; + function decorate(val) { + if (!val.use || !val.run) { + base(val); + } + } + + return app; +}; /***/ }), -/* 493 */ +/* 457 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ +"use strict"; -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } +var utils = {}; - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - // other objects - var type = toString.call(val); +/** + * Lazily required module dependencies + */ - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } +utils.define = __webpack_require__(386); +utils.isObject = __webpack_require__(404); - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } +utils.isString = function(val) { + return val && typeof val === 'string'; +}; - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } +/** + * Expose `utils` modules + */ - // must be a plain object - return 'object'; -}; +module.exports = utils; /***/ }), -/* 494 */ +/* 458 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -45725,14 +42639,14 @@ module.exports = function kindOf(val) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(495); + module.exports = __webpack_require__(459); } else { - module.exports = __webpack_require__(498); + module.exports = __webpack_require__(462); } /***/ }), -/* 495 */ +/* 459 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -45741,7 +42655,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(496); +exports = module.exports = __webpack_require__(460); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -45923,7 +42837,7 @@ function localstorage() { /***/ }), -/* 496 */ +/* 460 */ /***/ (function(module, exports, __webpack_require__) { @@ -45939,7 +42853,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(497); +exports.humanize = __webpack_require__(461); /** * The currently active debug mode names, and names to skip. @@ -46131,7 +43045,7 @@ function coerce(val) { /***/ }), -/* 497 */ +/* 461 */ /***/ (function(module, exports) { /** @@ -46289,14 +43203,14 @@ function plural(ms, n, name) { /***/ }), -/* 498 */ +/* 462 */ /***/ (function(module, exports, __webpack_require__) { /** * Module dependencies. */ -var tty = __webpack_require__(499); +var tty = __webpack_require__(463); var util = __webpack_require__(29); /** @@ -46305,7 +43219,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(496); +exports = module.exports = __webpack_require__(460); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -46484,7 +43398,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(500); + var net = __webpack_require__(464); stream = new net.Socket({ fd: fd, readable: false, @@ -46543,19 +43457,19 @@ exports.enable(load()); /***/ }), -/* 499 */ +/* 463 */ /***/ (function(module, exports) { module.exports = require("tty"); /***/ }), -/* 500 */ +/* 464 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 501 */ +/* 465 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46565,9 +43479,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(398); -exports.SourceMap = __webpack_require__(502); -exports.sourceMapResolve = __webpack_require__(513); +exports.extend = __webpack_require__(394); +exports.SourceMap = __webpack_require__(466); +exports.sourceMapResolve = __webpack_require__(477); /** * Convert backslash in the given string to forward slashes @@ -46610,7 +43524,7 @@ exports.last = function(arr, n) { /***/ }), -/* 502 */ +/* 466 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -46618,13 +43532,13 @@ exports.last = function(arr, n) { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(503).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(509).SourceMapConsumer; -exports.SourceNode = __webpack_require__(512).SourceNode; +exports.SourceMapGenerator = __webpack_require__(467).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(473).SourceMapConsumer; +exports.SourceNode = __webpack_require__(476).SourceNode; /***/ }), -/* 503 */ +/* 467 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -46634,10 +43548,10 @@ exports.SourceNode = __webpack_require__(512).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(504); -var util = __webpack_require__(506); -var ArraySet = __webpack_require__(507).ArraySet; -var MappingList = __webpack_require__(508).MappingList; +var base64VLQ = __webpack_require__(468); +var util = __webpack_require__(470); +var ArraySet = __webpack_require__(471).ArraySet; +var MappingList = __webpack_require__(472).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -47046,7 +43960,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 504 */ +/* 468 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -47086,7 +44000,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(505); +var base64 = __webpack_require__(469); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -47192,7 +44106,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 505 */ +/* 469 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -47265,7 +44179,7 @@ exports.decode = function (charCode) { /***/ }), -/* 506 */ +/* 470 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -47688,7 +44602,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 507 */ +/* 471 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -47698,7 +44612,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(506); +var util = __webpack_require__(470); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -47815,7 +44729,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 508 */ +/* 472 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -47825,7 +44739,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(506); +var util = __webpack_require__(470); /** * Determine whether mappingB is after mappingA with respect to generated @@ -47900,7 +44814,7 @@ exports.MappingList = MappingList; /***/ }), -/* 509 */ +/* 473 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -47910,11 +44824,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(506); -var binarySearch = __webpack_require__(510); -var ArraySet = __webpack_require__(507).ArraySet; -var base64VLQ = __webpack_require__(504); -var quickSort = __webpack_require__(511).quickSort; +var util = __webpack_require__(470); +var binarySearch = __webpack_require__(474); +var ArraySet = __webpack_require__(471).ArraySet; +var base64VLQ = __webpack_require__(468); +var quickSort = __webpack_require__(475).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -48988,7 +45902,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 510 */ +/* 474 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -49105,7 +46019,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 511 */ +/* 475 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -49225,7 +46139,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 512 */ +/* 476 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -49235,8 +46149,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(503).SourceMapGenerator; -var util = __webpack_require__(506); +var SourceMapGenerator = __webpack_require__(467).SourceMapGenerator; +var util = __webpack_require__(470); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -49644,17 +46558,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 513 */ +/* 477 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(514) -var resolveUrl = __webpack_require__(515) -var decodeUriComponent = __webpack_require__(516) -var urix = __webpack_require__(518) -var atob = __webpack_require__(519) +var sourceMappingURL = __webpack_require__(478) +var resolveUrl = __webpack_require__(479) +var decodeUriComponent = __webpack_require__(480) +var urix = __webpack_require__(482) +var atob = __webpack_require__(483) @@ -49952,7 +46866,7 @@ module.exports = { /***/ }), -/* 514 */ +/* 478 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -50015,13 +46929,13 @@ void (function(root, factory) { /***/ }), -/* 515 */ +/* 479 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var url = __webpack_require__(74) +var url = __webpack_require__(73) function resolveUrl(/* ...urls */) { return Array.prototype.reduce.call(arguments, function(resolved, nextUrl) { @@ -50033,13 +46947,13 @@ module.exports = resolveUrl /***/ }), -/* 516 */ +/* 480 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(517) +var decodeUriComponent = __webpack_require__(481) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -50050,7 +46964,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 517 */ +/* 481 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50151,7 +47065,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 518 */ +/* 482 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -50174,7 +47088,7 @@ module.exports = urix /***/ }), -/* 519 */ +/* 483 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50188,7 +47102,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 520 */ +/* 484 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50196,8 +47110,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(23); var path = __webpack_require__(16); -var define = __webpack_require__(477); -var utils = __webpack_require__(501); +var define = __webpack_require__(386); +var utils = __webpack_require__(465); /** * Expose `mixin()`. @@ -50340,19 +47254,19 @@ exports.comment = function(node) { /***/ }), -/* 521 */ +/* 485 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(485); +var use = __webpack_require__(456); var util = __webpack_require__(29); -var Cache = __webpack_require__(522); -var define = __webpack_require__(477); -var debug = __webpack_require__(494)('snapdragon:parser'); -var Position = __webpack_require__(523); -var utils = __webpack_require__(501); +var Cache = __webpack_require__(486); +var define = __webpack_require__(386); +var debug = __webpack_require__(458)('snapdragon:parser'); +var Position = __webpack_require__(487); +var utils = __webpack_require__(465); /** * Create a new `Parser` with the given `input` and `options`. @@ -50880,7 +47794,7 @@ module.exports = Parser; /***/ }), -/* 522 */ +/* 486 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50987,13 +47901,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 523 */ +/* 487 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(477); +var define = __webpack_require__(386); /** * Store position for a node @@ -51008,14 +47922,14 @@ module.exports = function Position(start, parser) { /***/ }), -/* 524 */ +/* 488 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(525); -var extglob = __webpack_require__(535); +var nanomatch = __webpack_require__(489); +var extglob = __webpack_require__(500); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -51092,7 +48006,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 525 */ +/* 489 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -51103,17 +48017,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(29); -var toRegex = __webpack_require__(389); -var extend = __webpack_require__(398); +var toRegex = __webpack_require__(385); +var extend = __webpack_require__(394); /** * Local dependencies */ -var compilers = __webpack_require__(526); -var parsers = __webpack_require__(527); -var cache = __webpack_require__(529); -var utils = __webpack_require__(531); +var compilers = __webpack_require__(490); +var parsers = __webpack_require__(491); +var cache = __webpack_require__(493); +var utils = __webpack_require__(495); var MAX_LENGTH = 1024 * 64; /** @@ -51942,7 +48856,7 @@ module.exports = nanomatch; /***/ }), -/* 526 */ +/* 490 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52268,15 +49182,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 527 */ +/* 491 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(400); -var toRegex = __webpack_require__(389); -var isOdd = __webpack_require__(528); +var regexNot = __webpack_require__(396); +var toRegex = __webpack_require__(385); +var isOdd = __webpack_require__(492); /** * Characters to use in negation regex (we want to "not" match @@ -52663,7 +49577,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 528 */ +/* 492 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52676,7 +49590,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(419); +var isNumber = __webpack_require__(408); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -52690,14 +49604,14 @@ module.exports = function isOdd(i) { /***/ }), -/* 529 */ +/* 493 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(530))(); +module.exports = new (__webpack_require__(494))(); /***/ }), -/* 530 */ +/* 494 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52710,7 +49624,7 @@ module.exports = new (__webpack_require__(530))(); -var MapCache = __webpack_require__(522); +var MapCache = __webpack_require__(486); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -52832,7 +49746,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 531 */ +/* 495 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52845,13 +49759,13 @@ var path = __webpack_require__(16); * Module dependencies */ -var Snapdragon = __webpack_require__(428); -utils.define = __webpack_require__(402); -utils.diff = __webpack_require__(532); -utils.extend = __webpack_require__(398); -utils.pick = __webpack_require__(533); -utils.typeOf = __webpack_require__(534); -utils.unique = __webpack_require__(401); +var Snapdragon = __webpack_require__(424); +utils.define = __webpack_require__(496); +utils.diff = __webpack_require__(497); +utils.extend = __webpack_require__(394); +utils.pick = __webpack_require__(498); +utils.typeOf = __webpack_require__(499); +utils.unique = __webpack_require__(397); /** * Returns true if the given value is effectively an empty string @@ -53217,7 +50131,45 @@ utils.unixify = function(options) { /***/ }), -/* 532 */ +/* 496 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * define-property + * + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. + */ + + + +var isDescriptor = __webpack_require__(416); + +module.exports = function defineProperty(obj, prop, val) { + if (typeof obj !== 'object' && typeof obj !== 'function') { + throw new TypeError('expected an object or function.'); + } + + if (typeof prop !== 'string') { + throw new TypeError('expected `prop` to be a string.'); + } + + if (isDescriptor(val) && ('set' in val || 'get' in val)) { + return Object.defineProperty(obj, prop, val); + } + + return Object.defineProperty(obj, prop, { + configurable: true, + enumerable: false, + writable: true, + value: val + }); +}; + + +/***/ }), +/* 497 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53271,7 +50223,7 @@ function diffArray(one, two) { /***/ }), -/* 533 */ +/* 498 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53284,7 +50236,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(415); +var isObject = __webpack_require__(404); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -53313,7 +50265,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 534 */ +/* 499 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -53466,7 +50418,7 @@ function isBuffer(val) { /***/ }), -/* 535 */ +/* 500 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53476,18 +50428,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(398); -var unique = __webpack_require__(401); -var toRegex = __webpack_require__(389); +var extend = __webpack_require__(394); +var unique = __webpack_require__(397); +var toRegex = __webpack_require__(385); /** * Local dependencies */ -var compilers = __webpack_require__(536); -var parsers = __webpack_require__(549); -var Extglob = __webpack_require__(551); -var utils = __webpack_require__(550); +var compilers = __webpack_require__(501); +var parsers = __webpack_require__(507); +var Extglob = __webpack_require__(509); +var utils = __webpack_require__(508); var MAX_LENGTH = 1024 * 64; /** @@ -53804,13 +50756,13 @@ module.exports = extglob; /***/ }), -/* 536 */ +/* 501 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(537); +var brackets = __webpack_require__(502); /** * Extglob compilers @@ -53980,7 +50932,7 @@ module.exports = function(extglob) { /***/ }), -/* 537 */ +/* 502 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53990,17 +50942,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(538); -var parsers = __webpack_require__(540); +var compilers = __webpack_require__(503); +var parsers = __webpack_require__(505); /** * Module dependencies */ -var debug = __webpack_require__(494)('expand-brackets'); -var extend = __webpack_require__(398); -var Snapdragon = __webpack_require__(428); -var toRegex = __webpack_require__(389); +var debug = __webpack_require__(458)('expand-brackets'); +var extend = __webpack_require__(394); +var Snapdragon = __webpack_require__(424); +var toRegex = __webpack_require__(385); /** * Parses the given POSIX character class `pattern` and returns a @@ -54158,1047 +51110,445 @@ brackets.makeRe = function(pattern, options) { * // 'bracket.literal': [Function], * // 'bracket.close': [Function] }, * // output: '[a-zA-Z]', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: [ [Object], [Object], [Object] ] }, - * // parsingErrors: [] } - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} - * @api public - */ - -brackets.create = function(pattern, options) { - var snapdragon = (options && options.snapdragon) || new Snapdragon(options); - compilers(snapdragon); - parsers(snapdragon); - - var ast = snapdragon.parse(pattern, options); - ast.input = pattern; - var res = snapdragon.compile(ast, options); - res.input = pattern; - return res; -}; - -/** - * Expose `brackets` constructor, parsers and compilers - */ - -brackets.compilers = compilers; -brackets.parsers = parsers; - -/** - * Expose `brackets` - * @type {Function} - */ - -module.exports = brackets; - - -/***/ }), -/* 538 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var posix = __webpack_require__(539); - -module.exports = function(brackets) { - brackets.compiler - - /** - * Escaped characters - */ - - .set('escape', function(node) { - return this.emit('\\' + node.val.replace(/^\\/, ''), node); - }) - - /** - * Text - */ - - .set('text', function(node) { - return this.emit(node.val.replace(/([{}])/g, '\\$1'), node); - }) - - /** - * POSIX character classes - */ - - .set('posix', function(node) { - if (node.val === '[::]') { - return this.emit('\\[::\\]', node); - } - - var val = posix[node.inner]; - if (typeof val === 'undefined') { - val = '[' + node.inner + ']'; - } - return this.emit(val, node); - }) - - /** - * Non-posix brackets - */ - - .set('bracket', function(node) { - return this.mapVisit(node.nodes); - }) - .set('bracket.open', function(node) { - return this.emit(node.val, node); - }) - .set('bracket.inner', function(node) { - var inner = node.val; - - if (inner === '[' || inner === ']') { - return this.emit('\\' + node.val, node); - } - if (inner === '^]') { - return this.emit('^\\]', node); - } - if (inner === '^') { - return this.emit('^', node); - } - - if (/-/.test(inner) && !/(\d-\d|\w-\w)/.test(inner)) { - inner = inner.split('-').join('\\-'); - } - - var isNegated = inner.charAt(0) === '^'; - // add slashes to negated brackets, per spec - if (isNegated && inner.indexOf('/') === -1) { - inner += '/'; - } - if (isNegated && inner.indexOf('.') === -1) { - inner += '.'; - } - - // don't unescape `0` (octal literal) - inner = inner.replace(/\\([1-9])/g, '$1'); - return this.emit(inner, node); - }) - .set('bracket.close', function(node) { - var val = node.val.replace(/^\\/, ''); - if (node.parent.escaped === true) { - return this.emit('\\' + val, node); - } - return this.emit(val, node); - }); -}; - - -/***/ }), -/* 539 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * POSIX character classes - */ - -module.exports = { - alnum: 'a-zA-Z0-9', - alpha: 'a-zA-Z', - ascii: '\\x00-\\x7F', - blank: ' \\t', - cntrl: '\\x00-\\x1F\\x7F', - digit: '0-9', - graph: '\\x21-\\x7E', - lower: 'a-z', - print: '\\x20-\\x7E ', - punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', - space: ' \\t\\r\\n\\v\\f', - upper: 'A-Z', - word: 'A-Za-z0-9_', - xdigit: 'A-Fa-f0-9' -}; - - -/***/ }), -/* 540 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = __webpack_require__(541); -var define = __webpack_require__(542); - -/** - * Text regex - */ - -var TEXT_REGEX = '(\\[(?=.*\\])|\\])+'; -var not = utils.createRegex(TEXT_REGEX); - -/** - * Brackets parsers - */ - -function parsers(brackets) { - brackets.state = brackets.state || {}; - brackets.parser.sets.bracket = brackets.parser.sets.bracket || []; - brackets.parser - - .capture('escape', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^\\(.)/); - if (!m) return; - - return pos({ - type: 'escape', - val: m[0] - }); - }) - - /** - * Text parser - */ - - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - return pos({ - type: 'text', - val: m[0] - }); - }) - - /** - * POSIX character classes: "[[:alpha:][:digits:]]" - */ - - .capture('posix', function() { - var pos = this.position(); - var m = this.match(/^\[:(.*?):\](?=.*\])/); - if (!m) return; - - var inside = this.isInside('bracket'); - if (inside) { - brackets.posix++; - } - - return pos({ - type: 'posix', - insideBracket: inside, - inner: m[1], - val: m[0] - }); - }) - - /** - * Bracket (noop) - */ - - .capture('bracket', function() {}) - - /** - * Open: '[' - */ - - .capture('bracket.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\[(?=.*\])/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { - last.val = last.val.slice(0, last.val.length - 1); - return pos({ - type: 'escape', - val: m[0] - }); - } - - var open = pos({ - type: 'bracket.open', - val: m[0] - }); - - if (last.type === 'bracket.open' || this.isInside('bracket')) { - open.val = '\\' + open.val; - open.type = 'bracket.inner'; - open.escaped = true; - return open; - } - - var node = pos({ - type: 'bracket', - nodes: [open] - }); - - define(node, 'parent', prev); - define(open, 'parent', node); - this.push('bracket', node); - prev.nodes.push(node); - }) - - /** - * Bracket text - */ - - .capture('bracket.inner', function() { - if (!this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - var next = this.input.charAt(0); - var val = m[0]; - - var node = pos({ - type: 'bracket.inner', - val: val - }); - - if (val === '\\\\') { - return node; - } - - var first = val.charAt(0); - var last = val.slice(-1); - - if (first === '!') { - val = '^' + val.slice(1); - } - - if (last === '\\' || (val === '^' && next === ']')) { - val += this.input[0]; - this.consume(1); - } - - node.val = val; - return node; - }) - - /** - * Close: ']' - */ - - .capture('bracket.close', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\]/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { - last.val = last.val.slice(0, last.val.length - 1); - - return pos({ - type: 'escape', - val: m[0] - }); - } - - var node = pos({ - type: 'bracket.close', - rest: this.input, - val: m[0] - }); - - if (last.type === 'bracket.open') { - node.type = 'bracket.inner'; - node.escaped = true; - return node; - } - - var bracket = this.pop('bracket'); - if (!this.isType(bracket, 'bracket')) { - if (this.options.strict) { - throw new Error('missing opening "["'); - } - node.type = 'bracket.inner'; - node.escaped = true; - return node; - } - - bracket.nodes.push(node); - define(node, 'parent', bracket); - }); -} - -/** - * Brackets parsers - */ - -module.exports = parsers; - -/** - * Expose text regex - */ - -module.exports.TEXT_REGEX = TEXT_REGEX; - - -/***/ }), -/* 541 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var toRegex = __webpack_require__(389); -var regexNot = __webpack_require__(400); -var cached; - -/** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} - */ - -exports.last = function(arr) { - return arr[arr.length - 1]; -}; - -/** - * Create and cache regex to use for text nodes - */ - -exports.createRegex = function(pattern, include) { - if (cached) return cached; - var opts = {contains: true, strictClose: false}; - var not = regexNot.create(pattern, opts); - var re; - - if (typeof include === 'string') { - re = toRegex('^(?:' + include + '|' + not + ')', opts); - } else { - re = toRegex(not, opts); - } - - return (cached = re); -}; - - -/***/ }), -/* 542 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * // ast: + * // { type: 'root', + * // errors: [], + * // nodes: [ [Object], [Object], [Object] ] }, + * // parsingErrors: [] } + * ``` + * @param {String} `pattern` + * @param {Object} `options` + * @return {Object} + * @api public */ +brackets.create = function(pattern, options) { + var snapdragon = (options && options.snapdragon) || new Snapdragon(options); + compilers(snapdragon); + parsers(snapdragon); + var ast = snapdragon.parse(pattern, options); + ast.input = pattern; + var res = snapdragon.compile(ast, options); + res.input = pattern; + return res; +}; -var isDescriptor = __webpack_require__(543); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } +/** + * Expose `brackets` constructor, parsers and compilers + */ - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } +brackets.compilers = compilers; +brackets.parsers = parsers; - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } +/** + * Expose `brackets` + * @type {Function} + */ - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; +module.exports = brackets; /***/ }), -/* 543 */ +/* 503 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ +var posix = __webpack_require__(504); -var typeOf = __webpack_require__(544); -var isAccessor = __webpack_require__(545); -var isData = __webpack_require__(547); +module.exports = function(brackets) { + brackets.compiler -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; + /** + * Escaped characters + */ + .set('escape', function(node) { + return this.emit('\\' + node.val.replace(/^\\/, ''), node); + }) -/***/ }), -/* 544 */ -/***/ (function(module, exports) { + /** + * Text + */ -var toString = Object.prototype.toString; + .set('text', function(node) { + return this.emit(node.val.replace(/([{}])/g, '\\$1'), node); + }) -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ + /** + * POSIX character classes + */ -module.exports = function kindOf(val) { - var type = typeof val; + .set('posix', function(node) { + if (node.val === '[::]') { + return this.emit('\\[::\\]', node); + } - // primitivies - if (type === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (type === 'string' || val instanceof String) { - return 'string'; - } - if (type === 'number' || val instanceof Number) { - return 'number'; - } + var val = posix[node.inner]; + if (typeof val === 'undefined') { + val = '[' + node.inner + ']'; + } + return this.emit(val, node); + }) - // functions - if (type === 'function' || val instanceof Function) { - if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { - return 'generatorfunction'; - } - return 'function'; - } + /** + * Non-posix brackets + */ - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } + .set('bracket', function(node) { + return this.mapVisit(node.nodes); + }) + .set('bracket.open', function(node) { + return this.emit(node.val, node); + }) + .set('bracket.inner', function(node) { + var inner = node.val; - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } + if (inner === '[' || inner === ']') { + return this.emit('\\' + node.val, node); + } + if (inner === '^]') { + return this.emit('^\\]', node); + } + if (inner === '^') { + return this.emit('^', node); + } - // other objects - type = toString.call(val); + if (/-/.test(inner) && !/(\d-\d|\w-\w)/.test(inner)) { + inner = inner.split('-').join('\\-'); + } - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; - } + var isNegated = inner.charAt(0) === '^'; + // add slashes to negated brackets, per spec + if (isNegated && inner.indexOf('/') === -1) { + inner += '/'; + } + if (isNegated && inner.indexOf('.') === -1) { + inner += '.'; + } - // buffer - if (isBuffer(val)) { - return 'buffer'; - } + // don't unescape `0` (octal literal) + inner = inner.replace(/\\([1-9])/g, '$1'); + return this.emit(inner, node); + }) + .set('bracket.close', function(node) { + var val = node.val.replace(/^\\/, ''); + if (node.parent.escaped === true) { + return this.emit('\\' + val, node); + } + return this.emit(val, node); + }); +}; - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - if (type === '[object Map Iterator]') { - return 'mapiterator'; - } - if (type === '[object Set Iterator]') { - return 'setiterator'; - } - if (type === '[object String Iterator]') { - return 'stringiterator'; - } - if (type === '[object Array Iterator]') { - return 'arrayiterator'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - // must be a plain object - return 'object'; -}; +/***/ }), +/* 504 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * POSIX character classes */ -function isBuffer(val) { - return val.constructor - && typeof val.constructor.isBuffer === 'function' - && val.constructor.isBuffer(val); -} +module.exports = { + alnum: 'a-zA-Z0-9', + alpha: 'a-zA-Z', + ascii: '\\x00-\\x7F', + blank: ' \\t', + cntrl: '\\x00-\\x1F\\x7F', + digit: '0-9', + graph: '\\x21-\\x7E', + lower: 'a-z', + print: '\\x20-\\x7E ', + punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', + space: ' \\t\\r\\n\\v\\f', + upper: 'A-Z', + word: 'A-Za-z0-9_', + xdigit: 'A-Fa-f0-9' +}; /***/ }), -/* 545 */ +/* 505 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(546); -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } +var utils = __webpack_require__(506); +var define = __webpack_require__(386); - if (typeOf(obj) !== 'object') { - return false; - } +/** + * Text regex + */ - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } +var TEXT_REGEX = '(\\[(?=.*\\])|\\])+'; +var not = utils.createRegex(TEXT_REGEX); - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } +/** + * Brackets parsers + */ - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } +function parsers(brackets) { + brackets.state = brackets.state || {}; + brackets.parser.sets.bracket = brackets.parser.sets.bracket || []; + brackets.parser - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } + .capture('escape', function() { + if (this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(/^\\(.)/); + if (!m) return; - if (typeOf(obj[key]) === accessor[key]) { - continue; - } + return pos({ + type: 'escape', + val: m[0] + }); + }) - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} + /** + * Text parser + */ -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} + .capture('text', function() { + if (this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(not); + if (!m || !m[0]) return; -/** - * Expose `isAccessorDescriptor` - */ + return pos({ + type: 'text', + val: m[0] + }); + }) -module.exports = isAccessorDescriptor; + /** + * POSIX character classes: "[[:alpha:][:digits:]]" + */ + .capture('posix', function() { + var pos = this.position(); + var m = this.match(/^\[:(.*?):\](?=.*\])/); + if (!m) return; -/***/ }), -/* 546 */ -/***/ (function(module, exports, __webpack_require__) { + var inside = this.isInside('bracket'); + if (inside) { + brackets.posix++; + } -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; + return pos({ + type: 'posix', + insideBracket: inside, + inner: m[1], + val: m[0] + }); + }) -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ + /** + * Bracket (noop) + */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } + .capture('bracket', function() {}) - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } + /** + * Open: '[' + */ - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } + .capture('bracket.open', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\[(?=.*\])/); + if (!m) return; - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } + var prev = this.prev(); + var last = utils.last(prev.nodes); - // other objects - var type = toString.call(val); + if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { + last.val = last.val.slice(0, last.val.length - 1); + return pos({ + type: 'escape', + val: m[0] + }); + } - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } + var open = pos({ + type: 'bracket.open', + val: m[0] + }); - // buffer - if (isBuffer(val)) { - return 'buffer'; - } + if (last.type === 'bracket.open' || this.isInside('bracket')) { + open.val = '\\' + open.val; + open.type = 'bracket.inner'; + open.escaped = true; + return open; + } - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } + var node = pos({ + type: 'bracket', + nodes: [open] + }); - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } + define(node, 'parent', prev); + define(open, 'parent', node); + this.push('bracket', node); + prev.nodes.push(node); + }) - // must be a plain object - return 'object'; -}; + /** + * Bracket text + */ + .capture('bracket.inner', function() { + if (!this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(not); + if (!m || !m[0]) return; -/***/ }), -/* 547 */ -/***/ (function(module, exports, __webpack_require__) { + var next = this.input.charAt(0); + var val = m[0]; -"use strict"; -/*! - * is-data-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ + var node = pos({ + type: 'bracket.inner', + val: val + }); + if (val === '\\\\') { + return node; + } + var first = val.charAt(0); + var last = val.slice(-1); -var typeOf = __webpack_require__(548); + if (first === '!') { + val = '^' + val.slice(1); + } -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' -}; + if (last === '\\' || (val === '^' && next === ']')) { + val += this.input[0]; + this.consume(1); + } -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; - } + node.val = val; + return node; + }) - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } + /** + * Close: ']' + */ - if (!('value' in obj) && !('writable' in obj)) { - return false; - } + .capture('bracket.close', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\]/); + if (!m) return; - for (var key in obj) { - if (key === 'value') continue; + var prev = this.prev(); + var last = utils.last(prev.nodes); - if (!data.hasOwnProperty(key)) { - continue; - } + if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { + last.val = last.val.slice(0, last.val.length - 1); - if (typeOf(obj[key]) === data[key]) { - continue; - } + return pos({ + type: 'escape', + val: m[0] + }); + } - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} + var node = pos({ + type: 'bracket.close', + rest: this.input, + val: m[0] + }); -/** - * Expose `isDataDescriptor` - */ + if (last.type === 'bracket.open') { + node.type = 'bracket.inner'; + node.escaped = true; + return node; + } -module.exports = isDataDescriptor; + var bracket = this.pop('bracket'); + if (!this.isType(bracket, 'bracket')) { + if (this.options.strict) { + throw new Error('missing opening "["'); + } + node.type = 'bracket.inner'; + node.escaped = true; + return node; + } + bracket.nodes.push(node); + define(node, 'parent', bracket); + }); +} -/***/ }), -/* 548 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * Brackets parsers + */ -var isBuffer = __webpack_require__(395); -var toString = Object.prototype.toString; +module.exports = parsers; /** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type + * Expose text regex */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } +module.exports.TEXT_REGEX = TEXT_REGEX; - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } +/***/ }), +/* 506 */ +/***/ (function(module, exports, __webpack_require__) { - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } +"use strict"; - // other objects - var type = toString.call(val); - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } +var toRegex = __webpack_require__(385); +var regexNot = __webpack_require__(396); +var cached; - // buffer - if (isBuffer(val)) { - return 'buffer'; - } +/** + * Get the last element from `array` + * @param {Array} `array` + * @return {*} + */ - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } +exports.last = function(arr) { + return arr[arr.length - 1]; +}; - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; +/** + * Create and cache regex to use for text nodes + */ + +exports.createRegex = function(pattern, include) { + if (cached) return cached; + var opts = {contains: true, strictClose: false}; + var not = regexNot.create(pattern, opts); + var re; + + if (typeof include === 'string') { + re = toRegex('^(?:' + include + '|' + not + ')', opts); + } else { + re = toRegex(not, opts); } - // must be a plain object - return 'object'; + return (cached = re); }; /***/ }), -/* 549 */ +/* 507 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(537); -var define = __webpack_require__(402); -var utils = __webpack_require__(550); +var brackets = __webpack_require__(502); +var define = __webpack_require__(496); +var utils = __webpack_require__(508); /** * Characters to use in text regex (we want to "not" match @@ -55353,14 +51703,14 @@ module.exports = parsers; /***/ }), -/* 550 */ +/* 508 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(400); -var Cache = __webpack_require__(530); +var regex = __webpack_require__(396); +var Cache = __webpack_require__(494); /** * Utils @@ -55429,7 +51779,7 @@ utils.createRegex = function(str) { /***/ }), -/* 551 */ +/* 509 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55439,16 +51789,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(428); -var define = __webpack_require__(402); -var extend = __webpack_require__(398); +var Snapdragon = __webpack_require__(424); +var define = __webpack_require__(496); +var extend = __webpack_require__(394); /** * Local dependencies */ -var compilers = __webpack_require__(536); -var parsers = __webpack_require__(549); +var compilers = __webpack_require__(501); +var parsers = __webpack_require__(507); /** * Customize Snapdragon parser and renderer @@ -55514,16 +51864,16 @@ module.exports = Extglob; /***/ }), -/* 552 */ +/* 510 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(535); -var nanomatch = __webpack_require__(525); -var regexNot = __webpack_require__(400); -var toRegex = __webpack_require__(389); +var extglob = __webpack_require__(500); +var nanomatch = __webpack_require__(489); +var regexNot = __webpack_require__(396); +var toRegex = __webpack_require__(385); var not; /** @@ -55604,14 +51954,14 @@ function textRegex(pattern) { /***/ }), -/* 553 */ +/* 511 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(530))(); +module.exports = new (__webpack_require__(494))(); /***/ }), -/* 554 */ +/* 512 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55624,13 +51974,13 @@ var path = __webpack_require__(16); * Module dependencies */ -var Snapdragon = __webpack_require__(428); -utils.define = __webpack_require__(402); -utils.diff = __webpack_require__(532); -utils.extend = __webpack_require__(398); -utils.pick = __webpack_require__(533); -utils.typeOf = __webpack_require__(555); -utils.unique = __webpack_require__(401); +var Snapdragon = __webpack_require__(424); +utils.define = __webpack_require__(496); +utils.diff = __webpack_require__(497); +utils.extend = __webpack_require__(394); +utils.pick = __webpack_require__(498); +utils.typeOf = __webpack_require__(513); +utils.unique = __webpack_require__(397); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -55927,7 +52277,7 @@ utils.unixify = function(options) { /***/ }), -/* 555 */ +/* 513 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -56062,7 +52412,7 @@ function isBuffer(val) { /***/ }), -/* 556 */ +/* 514 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56078,8 +52428,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(557); -var reader_1 = __webpack_require__(570); +var readdir = __webpack_require__(515); +var reader_1 = __webpack_require__(528); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -56115,15 +52465,15 @@ exports.default = ReaderAsync; /***/ }), -/* 557 */ +/* 515 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(558); -const readdirAsync = __webpack_require__(566); -const readdirStream = __webpack_require__(569); +const readdirSync = __webpack_require__(516); +const readdirAsync = __webpack_require__(524); +const readdirStream = __webpack_require__(527); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -56207,7 +52557,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 558 */ +/* 516 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56215,11 +52565,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(559); +const DirectoryReader = __webpack_require__(517); let syncFacade = { - fs: __webpack_require__(564), - forEach: __webpack_require__(565), + fs: __webpack_require__(522), + forEach: __webpack_require__(523), sync: true }; @@ -56248,7 +52598,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 559 */ +/* 517 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56257,9 +52607,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(28).Readable; const EventEmitter = __webpack_require__(45).EventEmitter; const path = __webpack_require__(16); -const normalizeOptions = __webpack_require__(560); -const stat = __webpack_require__(562); -const call = __webpack_require__(563); +const normalizeOptions = __webpack_require__(518); +const stat = __webpack_require__(520); +const call = __webpack_require__(521); /** * Asynchronously reads the contents of a directory and streams the results @@ -56635,14 +52985,14 @@ module.exports = DirectoryReader; /***/ }), -/* 560 */ +/* 518 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(561); +const globToRegExp = __webpack_require__(519); module.exports = normalizeOptions; @@ -56819,7 +53169,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 561 */ +/* 519 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -56956,13 +53306,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 562 */ +/* 520 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(563); +const call = __webpack_require__(521); module.exports = stat; @@ -57037,7 +53387,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 563 */ +/* 521 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57098,14 +53448,14 @@ function callOnce (fn) { /***/ }), -/* 564 */ +/* 522 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const call = __webpack_require__(563); +const call = __webpack_require__(521); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -57169,7 +53519,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 565 */ +/* 523 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57198,7 +53548,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 566 */ +/* 524 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57206,12 +53556,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(567); -const DirectoryReader = __webpack_require__(559); +const maybe = __webpack_require__(525); +const DirectoryReader = __webpack_require__(517); let asyncFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(568), + forEach: __webpack_require__(526), async: true }; @@ -57253,7 +53603,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 567 */ +/* 525 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57280,7 +53630,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 568 */ +/* 526 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57316,7 +53666,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 569 */ +/* 527 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57324,11 +53674,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(559); +const DirectoryReader = __webpack_require__(517); let streamFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(568), + forEach: __webpack_require__(526), async: true }; @@ -57348,15 +53698,15 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 570 */ +/* 528 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var deep_1 = __webpack_require__(571); -var entry_1 = __webpack_require__(574); +var deep_1 = __webpack_require__(529); +var entry_1 = __webpack_require__(532); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -57422,15 +53772,15 @@ exports.default = Reader; /***/ }), -/* 571 */ +/* 529 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var arrayUtils = __webpack_require__(572); -var pathUtils = __webpack_require__(573); -var patternUtils = __webpack_require__(382); +var arrayUtils = __webpack_require__(530); +var pathUtils = __webpack_require__(531); +var patternUtils = __webpack_require__(378); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -57505,7 +53855,7 @@ exports.default = DeepFilter; /***/ }), -/* 572 */ +/* 530 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57528,7 +53878,7 @@ exports.max = max; /***/ }), -/* 573 */ +/* 531 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57546,13 +53896,13 @@ exports.isDotDirectory = isDotDirectory; /***/ }), -/* 574 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(382); +var patternUtils = __webpack_require__(378); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -57624,7 +53974,7 @@ exports.default = DeepFilter; /***/ }), -/* 575 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57641,8 +53991,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(28); -var readdir = __webpack_require__(557); -var reader_1 = __webpack_require__(570); +var readdir = __webpack_require__(515); +var reader_1 = __webpack_require__(528); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -57685,7 +54035,7 @@ exports.default = ReaderStream; /***/ }), -/* 576 */ +/* 534 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57701,8 +54051,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(557); -var reader_1 = __webpack_require__(570); +var readdir = __webpack_require__(515); +var reader_1 = __webpack_require__(528); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -57737,13 +54087,13 @@ exports.default = ReaderSync; /***/ }), -/* 577 */ +/* 535 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const arrify = __webpack_require__(374); +const arrify = __webpack_require__(370); const pathType = __webpack_require__(63); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -57792,17 +54142,17 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 578 */ +/* 536 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); const path = __webpack_require__(16); -const fastGlob = __webpack_require__(376); -const gitIgnore = __webpack_require__(579); -const pify = __webpack_require__(580); -const slash = __webpack_require__(581); +const fastGlob = __webpack_require__(372); +const gitIgnore = __webpack_require__(537); +const pify = __webpack_require__(62); +const slash = __webpack_require__(538); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -57894,7 +54244,7 @@ module.exports.sync = o => { /***/ }), -/* 579 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58326,98 +54676,7 @@ typeof process !== 'undefined' && (process.env && process.env.IGNORE_TEST_WIN32 /***/ }), -/* 580 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); - - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } - - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); - } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } - - resolve(results); - } else { - resolve(result); - } - }); - } - - fn.apply(this, args); - }); -}; - -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); - - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); - }; - - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } - - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; - } - - return ret; -}; - - -/***/ }), -/* 581 */ +/* 538 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58435,17 +54694,17 @@ module.exports = function (str) { /***/ }), -/* 582 */ +/* 539 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); const fsConstants = __webpack_require__(23).constants; -const {Buffer} = __webpack_require__(583); -const CpFileError = __webpack_require__(585); -const fs = __webpack_require__(587); -const ProgressEmitter = __webpack_require__(589); +const {Buffer} = __webpack_require__(540); +const CpFileError = __webpack_require__(542); +const fs = __webpack_require__(544); +const ProgressEmitter = __webpack_require__(545); module.exports = (src, dest, opts) => { if (!src || !dest) { @@ -58595,11 +54854,11 @@ module.exports.sync = (src, dest, opts) => { /***/ }), -/* 583 */ +/* 540 */ /***/ (function(module, exports, __webpack_require__) { /* eslint-disable node/no-deprecated-api */ -var buffer = __webpack_require__(584) +var buffer = __webpack_require__(541) var Buffer = buffer.Buffer // alternative to using Object.keys for old browsers @@ -58663,18 +54922,18 @@ SafeBuffer.allocUnsafeSlow = function (size) { /***/ }), -/* 584 */ +/* 541 */ /***/ (function(module, exports) { module.exports = require("buffer"); /***/ }), -/* 585 */ +/* 542 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(586); +const NestedError = __webpack_require__(543); class CpFileError extends NestedError { constructor(message, nested) { @@ -58688,7 +54947,7 @@ module.exports = CpFileError; /***/ }), -/* 586 */ +/* 543 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(43); @@ -58742,15 +55001,15 @@ module.exports = NestedError; /***/ }), -/* 587 */ +/* 544 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(22); -const makeDir = __webpack_require__(91); -const pify = __webpack_require__(588); -const CpFileError = __webpack_require__(585); +const makeDir = __webpack_require__(90); +const pify = __webpack_require__(62); +const CpFileError = __webpack_require__(542); const fsP = pify(fs); @@ -58895,98 +55154,7 @@ if (fs.copyFileSync) { /***/ }), -/* 588 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); - - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } - - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); - } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } - - resolve(results); - } else { - resolve(result); - } - }); - } - - fn.apply(this, args); - }); -}; - -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); - - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); - }; - - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } - - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; - } - - return ret; -}; - - -/***/ }), -/* 589 */ +/* 545 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59027,12 +55195,12 @@ module.exports = ProgressEmitter; /***/ }), -/* 590 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(586); +const NestedError = __webpack_require__(543); class CpyError extends NestedError { constructor(message, nested) { @@ -59046,7 +55214,7 @@ module.exports = CpyError; /***/ }), -/* 591 */ +/* 547 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json index 69830ad22b4bf..6248e919976db 100644 --- a/packages/kbn-pm/package.json +++ b/packages/kbn-pm/package.json @@ -20,12 +20,11 @@ "@types/globby": "^6.1.0", "@types/has-ansi": "^3.0.0", "@types/indent-string": "^3.0.0", - "@types/jest": "^23.3.1", "@types/lodash.clonedeepwith": "^4.5.3", "@types/log-symbols": "^2.0.0", "@types/mkdirp": "^0.5.2", "@types/ncp": "^2.0.1", - "@types/node": "^10.12.12", + "@types/node": "^10.12.27", "@types/ora": "^1.3.2", "@types/read-pkg": "^3.0.0", "@types/strip-ansi": "^3.0.0", @@ -62,7 +61,7 @@ "strong-log-transformer": "^2.1.0", "tempy": "^0.2.1", "ts-loader": "^5.2.2", - "typescript": "^3.0.3", + "typescript": "^3.3.3333", "unlazy-loader": "^0.1.3", "webpack": "^4.23.1", "webpack-cli": "^3.1.2", diff --git a/packages/kbn-pm/src/run.test.ts b/packages/kbn-pm/src/run.test.ts index 9b3d7707ae7b1..13cac6eb745ba 100644 --- a/packages/kbn-pm/src/run.test.ts +++ b/packages/kbn-pm/src/run.test.ts @@ -116,9 +116,7 @@ test('respects both `include` and `exclude` filters if specified at the same tim }); test('does not run command if all projects are filtered out', async () => { - const mockProcessExit = jest.spyOn(process, 'exit').mockImplementation(() => { - // noop - }); + const mockProcessExit = jest.spyOn(process, 'exit').mockReturnValue(undefined as never); await runCommand(command, { ...config, diff --git a/packages/kbn-pm/tsconfig.json b/packages/kbn-pm/tsconfig.json index c9c3344a1df3a..f7c8cdab16782 100644 --- a/packages/kbn-pm/tsconfig.json +++ b/packages/kbn-pm/tsconfig.json @@ -1,16 +1,15 @@ -{ - "extends": "../../tsconfig.json", - "exclude": [ - "dist" - ], - "include": [ - "./src/**/*.ts", - "./types/index.d.ts" - ], - "compilerOptions": { - "types": [ - "jest", - "node" - ] - } -} +{ + "extends": "../../tsconfig.json", + "exclude": [ + "dist" + ], + "include": [ + "./src/**/*.ts" + ], + "compilerOptions": { + "types": [ + "jest", + "node" + ] + } +} diff --git a/packages/kbn-pm/types/index.d.ts b/packages/kbn-pm/types/index.d.ts deleted file mode 100644 index 05e8d2b77e1c8..0000000000000 --- a/packages/kbn-pm/types/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/kbn-pm/types/jest/index.d.ts b/packages/kbn-pm/types/jest/index.d.ts deleted file mode 100644 index ce3f6dd5dcb02..0000000000000 --- a/packages/kbn-pm/types/jest/index.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -// Workaround for https://github.com/DefinitelyTyped/DefinitelyTyped/issues/17605. -declare namespace jest { - interface SpyInstance extends Mock { - mockImplementation(fn: (...args: any[]) => any): SpyInstance; - mockImplementationOnce(fn: (...args: any[]) => any): SpyInstance; - mockReturnThis(): SpyInstance; - mockReturnValue(value: any): SpyInstance; - mockReturnValueOnce(value: any): SpyInstance; - mockName(name: string): SpyInstance; - } -} diff --git a/packages/kbn-test/.babelrc b/packages/kbn-test/.babelrc deleted file mode 100644 index 7da72d1779128..0000000000000 --- a/packages/kbn-test/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["@kbn/babel-preset/node_preset"] -} diff --git a/packages/kbn-test/babel.config.js b/packages/kbn-test/babel.config.js new file mode 100644 index 0000000000000..962d7d3e05c55 --- /dev/null +++ b/packages/kbn-test/babel.config.js @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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. + */ + +module.exports = { + presets: ['@kbn/babel-preset/node_preset_7'], + ignore: ['**/*.test.js'], +}; diff --git a/packages/kbn-test/package.json b/packages/kbn-test/package.json index 22eb066751a13..aa57d854e14cc 100644 --- a/packages/kbn-test/package.json +++ b/packages/kbn-test/package.json @@ -5,14 +5,14 @@ "license": "Apache-2.0", "private": true, "scripts": { - "build": "babel src --out-dir target", - "kbn:bootstrap": "yarn build --quiet", + "build": "babel src --out-dir target --delete-dir-on-start --extensions .ts,.js,.tsx", + "kbn:bootstrap": "yarn build", "kbn:watch": "yarn build --watch" }, "devDependencies": { "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", - "babel-cli": "^6.26.0" + "@babel/cli": "^7.2.3" }, "dependencies": { "chalk": "^2.4.1", diff --git a/packages/kbn-test/tsconfig.json b/packages/kbn-test/tsconfig.json new file mode 100644 index 0000000000000..8d42818502289 --- /dev/null +++ b/packages/kbn-test/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "include": [ + "types/**/*" + ] +} diff --git a/packages/kbn-test/types/README.md b/packages/kbn-test/types/README.md new file mode 100644 index 0000000000000..5e4b2c6da6141 --- /dev/null +++ b/packages/kbn-test/types/README.md @@ -0,0 +1,6 @@ +# @kbn/test/types + +Shared types used by different parts of the tests + + - **`expect.js.d.ts`**: This is a fork of the expect.js types that have been slightly modified to only expose a module type for `import expect from 'expect.js'` statements. The `@types/expect.js` includes types for the `expect` global, which is useful for some uses of the library but conflicts with the jest types we use. Making the type "module only" prevents them from conflicting. + - **`ftr.d.ts`**: These types are generic types for using the functional test runner. They are here because we plan to move the functional test runner into the `@kbn/test` package at some point and having them here makes them a lot easier to import from all over the place like we do. \ No newline at end of file diff --git a/packages/kbn-test/types/expect.js.d.ts b/packages/kbn-test/types/expect.js.d.ts new file mode 100644 index 0000000000000..fd3cbd852f967 --- /dev/null +++ b/packages/kbn-test/types/expect.js.d.ts @@ -0,0 +1,225 @@ +// tslint:disable + +// Type definitions for expect.js 0.3.1 +// Project: https://github.com/Automattic/expect.js +// Definitions by: Teppei Sato +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// License: MIT + +declare module 'expect.js' { + function expect(target?: any): Root; + + interface Assertion { + /** + * Assert typeof / instanceof. + */ + an: An; + /** + * Check if the value is truthy + */ + ok(): void; + + /** + * Creates an anonymous function which calls fn with arguments. + */ + withArgs(...args: any[]): Root; + + /** + * Assert that the function throws. + * + * @param fn callback to match error string against + */ + throwError(fn?: (exception: any) => void): void; + + /** + * Assert that the function throws. + * + * @param fn callback to match error string against + */ + throwException(fn?: (exception: any) => void): void; + + /** + * Assert that the function throws. + * + * @param regexp regexp to match error string against + */ + throwError(regexp: RegExp): void; + + /** + * Assert that the function throws. + * + * @param fn callback to match error string against + */ + throwException(regexp: RegExp): void; + + /** + * Checks if the array is empty. + */ + empty(): Assertion; + + /** + * Checks if the obj exactly equals another. + */ + equal(obj: any): Assertion; + + /** + * Checks if the obj sortof equals another. + */ + eql(obj: any): Assertion; + + /** + * Assert within start to finish (inclusive). + * + * @param start + * @param finish + */ + within(start: number, finish: number): Assertion; + + /** + * Assert typeof. + */ + a(type: string): Assertion; + + /** + * Assert instanceof. + */ + a(type: Function): Assertion; + + /** + * Assert numeric value above n. + */ + greaterThan(n: number): Assertion; + + /** + * Assert numeric value above n. + */ + above(n: number): Assertion; + + /** + * Assert numeric value below n. + */ + lessThan(n: number): Assertion; + + /** + * Assert numeric value below n. + */ + below(n: number): Assertion; + + /** + * Assert string value matches regexp. + * + * @param regexp + */ + match(regexp: RegExp): Assertion; + + /** + * Assert property "length" exists and has value of n. + * + * @param n + */ + length(n: number): Assertion; + + /** + * Assert property name exists, with optional val. + * + * @param name + * @param val + */ + property(name: string, val?: any): Assertion; + + /** + * Assert that string contains str. + */ + contain(str: string): Assertion; + string(str: string): Assertion; + + /** + * Assert that the array contains obj. + */ + contain(obj: any): Assertion; + string(obj: any): Assertion; + + /** + * Assert exact keys or inclusion of keys by using the `.own` modifier. + */ + key(keys: string[]): Assertion; + /** + * Assert exact keys or inclusion of keys by using the `.own` modifier. + */ + key(...keys: string[]): Assertion; + /** + * Assert exact keys or inclusion of keys by using the `.own` modifier. + */ + keys(keys: string[]): Assertion; + /** + * Assert exact keys or inclusion of keys by using the `.own` modifier. + */ + keys(...keys: string[]): Assertion; + + /** + * Assert a failure. + */ + fail(message?: string): Assertion; + } + + interface Root extends Assertion { + not: Not; + to: To; + only: Only; + have: Have; + be: Be; + } + + interface Be extends Assertion { + /** + * Checks if the obj exactly equals another. + */ + (obj: any): Assertion; + + an: An; + } + + interface An extends Assertion { + /** + * Assert typeof. + */ + (type: string): Assertion; + + /** + * Assert instanceof. + */ + (type: Function): Assertion; + } + + interface Not extends NotBase { + to: ToBase; + } + + interface NotBase extends Assertion { + be: Be; + have: Have; + include: Assertion; + only: Only; + } + + interface To extends ToBase { + not: NotBase; + } + + interface ToBase extends Assertion { + be: Be; + have: Have; + include: Assertion; + only: Only; + } + + interface Only extends Assertion { + have: Have; + } + + interface Have extends Assertion { + own: Assertion; + } + + export default expect; +} diff --git a/packages/kbn-test/types/ftr.d.ts b/packages/kbn-test/types/ftr.d.ts new file mode 100644 index 0000000000000..8cc4253120635 --- /dev/null +++ b/packages/kbn-test/types/ftr.d.ts @@ -0,0 +1,80 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { DefaultServiceProviders } from '../../../src/functional_test_runner/types'; + +interface AsyncInstance { + /** + * Services that are initialized async are not ready before the tests execute, so you might need + * to call `init()` and await the promise it returns before interacting with the service + */ + init(): Promise; +} + +/** + * When a provider returns a promise it is initialized as an AsyncInstance that is a + * proxy to the eventual result with an added init() method which returns the eventual + * result. Automatically unwrap these promises and convert them to AsyncInstances + Instance + * types. + */ +type MaybeAsyncInstance = T extends Promise ? AsyncInstance & X : T; + +/** + * Convert a map of providers to a map of the instance types they provide, also converting + * promise types into the async instances that other providers will receive. + */ +type ProvidedTypeMap = { + [K in keyof T]: T[K] extends (...args: any[]) => any + ? MaybeAsyncInstance> + : never +}; + +export interface GenericFtrProviderContext< + ServiceProviders extends object, + PageObjectProviders extends object, + ServiceMap = ProvidedTypeMap, + PageObjectMap = ProvidedTypeMap +> { + /** + * Determine if a service is avaliable + * @param serviceName + */ + hasService(serviceName: K): serviceName is K; + hasService(serviceName: string): serviceName is keyof ServiceMap; + + /** + * Get the instance of a service, if the service is loaded async and the service needs to be used + * outside of a test/hook, then make sure to call its `.init()` method and await it's promise. + * @param serviceName + */ + getService(serviceName: T): ServiceMap[T]; + + /** + * Get a map of PageObjects + * @param pageObjects + */ + getPageObjects(pageObjects: K[]): Pick; + + /** + * Synchronously load a test file, can be called within a `describe()` block to add + * common setup/teardown steps to several suites + * @param path + */ + loadTestFile(path: string): void; +} diff --git a/src/cli/serve/integration_tests/reload_logging_config.test.js b/src/cli/serve/integration_tests/reload_logging_config.test.js index f3922b30ab709..fbb8fd0431e84 100644 --- a/src/cli/serve/integration_tests/reload_logging_config.test.js +++ b/src/cli/serve/integration_tests/reload_logging_config.test.js @@ -83,7 +83,7 @@ describe('Server logging configuration', function () { it('should be reloadable via SIGHUP process signaling', async function () { expect.assertions(3); - child = spawn(process.execPath, [kibanaPath, '--config', testConfigFile], { + child = spawn(process.execPath, [kibanaPath, '--config', testConfigFile, '--oss'], { stdio: 'pipe' }); @@ -174,6 +174,7 @@ describe('Server logging configuration', function () { child = spawn(process.execPath, [ kibanaPath, + '--oss', '--config', testConfigFile, '--logging.dest', logPath, '--plugins.initialize', 'false', diff --git a/src/core/public/chrome/chrome_service.test.ts b/src/core/public/chrome/chrome_service.test.ts index 9fd49fcdf6d4a..7526ff9305014 100644 --- a/src/core/public/chrome/chrome_service.test.ts +++ b/src/core/public/chrome/chrome_service.test.ts @@ -60,20 +60,12 @@ describe('start', () => { const startDeps = defaultStartDeps(); startDeps.injectedMetadata.getCspConfig.mockReturnValue({ warnLegacyBrowsers: true }); service.start(startDeps); - expect(startDeps.notifications.toasts.addWarning).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "Your browser does not meet the security requirements for Kibana.", - ], - ], - "results": Array [ - Object { - "isThrow": false, - "value": undefined, - }, + expect(startDeps.notifications.toasts.addWarning.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "Your browser does not meet the security requirements for Kibana.", ], -} +] `); }); diff --git a/src/core/public/core_system.test.ts b/src/core/public/core_system.test.ts index 07758b1970754..ffda17e340e11 100644 --- a/src/core/public/core_system.test.ts +++ b/src/core/public/core_system.test.ts @@ -23,24 +23,27 @@ import { FatalErrorsService } from './fatal_errors'; import { HttpService } from './http'; import { I18nService } from './i18n'; import { InjectedMetadataService } from './injected_metadata'; -import { LegacyPlatformService } from './legacy_platform'; +import { LegacyPlatformService } from './legacy'; import { NotificationsService } from './notifications'; import { UiSettingsService } from './ui_settings'; -const MockLegacyPlatformService = jest.fn( +const MockLegacyPlatformService = jest.fn( function _MockLegacyPlatformService(this: any) { this.start = jest.fn(); this.stop = jest.fn(); + return this; } ); -jest.mock('./legacy_platform', () => ({ + +jest.mock('./legacy', () => ({ LegacyPlatformService: MockLegacyPlatformService, })); const mockInjectedMetadataStart = {}; -const MockInjectedMetadataService = jest.fn( +const MockInjectedMetadataService = jest.fn( function _MockInjectedMetadataService(this: any) { this.start = jest.fn().mockReturnValue(mockInjectedMetadataStart); + return this; } ); jest.mock('./injected_metadata', () => ({ @@ -48,69 +51,81 @@ jest.mock('./injected_metadata', () => ({ })); const mockFatalErrorsStart = {}; -const MockFatalErrorsService = jest.fn(function _MockFatalErrorsService( +const MockFatalErrorsService = jest.fn(function _MockFatalErrorsService( this: any ) { this.start = jest.fn().mockReturnValue(mockFatalErrorsStart); this.add = jest.fn(); + return this; }); jest.mock('./fatal_errors', () => ({ FatalErrorsService: MockFatalErrorsService, })); const mockI18nStart = {}; -const MockI18nService = jest.fn(function _MockI18nService(this: any) { +const MockI18nService = jest.fn(function _MockI18nService(this: any) { this.start = jest.fn().mockReturnValue(mockI18nStart); this.stop = jest.fn(); + return this; }); jest.mock('./i18n', () => ({ I18nService: MockI18nService, })); const mockNotificationStart = {}; -const MockNotificationsService = jest.fn(function _MockNotificationsService( - this: any -) { - this.start = jest.fn().mockReturnValue(mockNotificationStart); - this.add = jest.fn(); - this.stop = jest.fn(); -}); +const MockNotificationsService = jest.fn( + function _MockNotificationsService(this: any) { + this.start = jest.fn().mockReturnValue(mockNotificationStart); + this.add = jest.fn(); + this.stop = jest.fn(); + return this; + } +); + jest.mock('./notifications', () => ({ NotificationsService: MockNotificationsService, })); const mockHttp = {}; -const MockHttpService = jest.fn(function _MockNotificationsService(this: any) { +const MockHttpService = jest.fn(function _MockNotificationsService(this: any) { this.start = jest.fn().mockReturnValue(mockHttp); this.stop = jest.fn(); + return this; }); jest.mock('./http', () => ({ HttpService: MockHttpService, })); const mockBasePathStart = {}; -const MockBasePathService = jest.fn(function _MockNotificationsService(this: any) { +const MockBasePathService = jest.fn(function _MockNotificationsService( + this: any +) { this.start = jest.fn().mockReturnValue(mockBasePathStart); + return this; }); jest.mock('./base_path', () => ({ BasePathService: MockBasePathService, })); const mockUiSettings = {}; -const MockUiSettingsService = jest.fn(function _MockNotificationsService( +const MockUiSettingsService = jest.fn(function _MockNotificationsService( this: any ) { this.start = jest.fn().mockReturnValue(mockUiSettings); this.stop = jest.fn(); + return this; }); jest.mock('./ui_settings', () => ({ UiSettingsService: MockUiSettingsService, })); const mockChromeStart = {}; -const MockChromeService = jest.fn(function _MockNotificationsService(this: any) { +const MockChromeService = jest.fn(function _MockNotificationsService( + this: any +) { this.start = jest.fn().mockReturnValue(mockChromeStart); this.stop = jest.fn(); + return this; }); jest.mock('./chrome', () => ({ ChromeService: MockChromeService, diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index a9916b6dea82b..ea934815fd448 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -25,7 +25,7 @@ import { FatalErrorsService } from './fatal_errors'; import { HttpService } from './http'; import { I18nService } from './i18n'; import { InjectedMetadataParams, InjectedMetadataService } from './injected_metadata'; -import { LegacyPlatformParams, LegacyPlatformService } from './legacy_platform'; +import { LegacyPlatformParams, LegacyPlatformService } from './legacy'; import { NotificationsService } from './notifications'; import { UiSettingsService } from './ui_settings'; diff --git a/src/core/public/fatal_errors/fatal_errors_screen.test.tsx b/src/core/public/fatal_errors/fatal_errors_screen.test.tsx index 89406baa35f3c..bdca3b18742d9 100644 --- a/src/core/public/fatal_errors/fatal_errors_screen.test.tsx +++ b/src/core/public/fatal_errors/fatal_errors_screen.test.tsx @@ -60,7 +60,7 @@ describe('reloading', () => { expect(locationReloadSpy).not.toHaveBeenCalled(); const [, handler] = addEventListenerSpy.mock.calls[0]; - handler(); + (handler as jest.Mock)(); expect(locationReloadSpy).toHaveBeenCalledTimes(1); }); }); diff --git a/src/core/public/fatal_errors/fatal_errors_service.test.ts b/src/core/public/fatal_errors/fatal_errors_service.test.ts index 36c6b209fb5c7..23895c8ce85cd 100644 --- a/src/core/public/fatal_errors/fatal_errors_service.test.ts +++ b/src/core/public/fatal_errors/fatal_errors_service.test.ts @@ -100,9 +100,7 @@ describe('start.add()', () => { it('exposes a function that passes its two arguments to fatalErrors.add()', () => { const { fatalErrors, i18n } = setup(); - jest.spyOn(fatalErrors, 'add').mockImplementation(() => { - /* noop */ - }); + jest.spyOn(fatalErrors, 'add').mockImplementation(() => undefined as never); expect(fatalErrors.add).not.toHaveBeenCalled(); const { add } = fatalErrors.start({ i18n }); diff --git a/src/core/public/injected_metadata/deep_freeze.test.ts b/src/core/public/injected_metadata/deep_freeze.test.ts index 3dc5a229e8146..b4531d80d0252 100644 --- a/src/core/public/injected_metadata/deep_freeze.test.ts +++ b/src/core/public/injected_metadata/deep_freeze.test.ts @@ -17,10 +17,6 @@ * under the License. */ -import { resolve } from 'path'; - -import execa from 'execa'; - import { deepFreeze } from './deep_freeze'; it('returns the first argument with all original references', () => { @@ -73,17 +69,3 @@ it('prevents reassigning items in a frozen array', () => { frozen.foo[0] = 2; }).toThrowError(`read only property '0'`); }); - -it('types return values to prevent mutations in typescript', async () => { - await expect( - execa.stdout('tsc', ['--noEmit'], { - cwd: resolve(__dirname, '__fixtures__/frozen_object_mutation'), - }) - ).rejects.toThrowErrorMatchingInlineSnapshot(` -"Command failed: tsc --noEmit - -index.ts(30,11): error TS2540: Cannot assign to 'baz' because it is a constant or a read-only property. -index.ts(40,10): error TS2540: Cannot assign to 'bar' because it is a constant or a read-only property. -" -`); -}); diff --git a/src/core/public/injected_metadata/__fixtures__/frozen_object_mutation/index.ts b/src/core/public/injected_metadata/integration_tests/__fixtures__/frozen_object_mutation/index.ts similarity index 95% rename from src/core/public/injected_metadata/__fixtures__/frozen_object_mutation/index.ts rename to src/core/public/injected_metadata/integration_tests/__fixtures__/frozen_object_mutation/index.ts index 0be915a4bde1f..9cf394fc2b0be 100644 --- a/src/core/public/injected_metadata/__fixtures__/frozen_object_mutation/index.ts +++ b/src/core/public/injected_metadata/integration_tests/__fixtures__/frozen_object_mutation/index.ts @@ -17,7 +17,7 @@ * under the License. */ -import { deepFreeze } from '../../deep_freeze'; +import { deepFreeze } from '../../../deep_freeze'; deepFreeze( { diff --git a/src/core/public/injected_metadata/__fixtures__/frozen_object_mutation/tsconfig.json b/src/core/public/injected_metadata/integration_tests/__fixtures__/frozen_object_mutation/tsconfig.json similarity index 100% rename from src/core/public/injected_metadata/__fixtures__/frozen_object_mutation/tsconfig.json rename to src/core/public/injected_metadata/integration_tests/__fixtures__/frozen_object_mutation/tsconfig.json diff --git a/src/legacy/core_plugins/elasticsearch/lib/create_data_cluster.js b/src/core/public/injected_metadata/integration_tests/deep_freeze.test.ts similarity index 59% rename from src/legacy/core_plugins/elasticsearch/lib/create_data_cluster.js rename to src/core/public/injected_metadata/integration_tests/deep_freeze.test.ts index c370d5b0f948a..36abb125e0ba3 100644 --- a/src/legacy/core_plugins/elasticsearch/lib/create_data_cluster.js +++ b/src/core/public/injected_metadata/integration_tests/deep_freeze.test.ts @@ -17,26 +17,20 @@ * under the License. */ -import { clientLogger } from './client_logger'; +import { resolve } from 'path'; -export function createDataCluster(server) { - const config = server.config(); - const ElasticsearchClientLogging = clientLogger(server); +import execa from 'execa'; - class DataClientLogging extends ElasticsearchClientLogging { - tags = ['data']; - logQueries = getConfig().logQueries; - } +it('types return values to prevent mutations in typescript', async () => { + await expect( + execa.stdout('tsc', ['--noEmit'], { + cwd: resolve(__dirname, '__fixtures__/frozen_object_mutation'), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(` +"Command failed: tsc --noEmit - function getConfig() { - return config.get('elasticsearch'); - } - - server.plugins.elasticsearch.createCluster( - 'data', - { - log: DataClientLogging, - ...getConfig() - } - ); -} +index.ts(30,11): error TS2540: Cannot assign to 'baz' because it is a read-only property. +index.ts(40,10): error TS2540: Cannot assign to 'bar' because it is a read-only property. +" +`); +}); diff --git a/src/core/public/legacy_platform/__snapshots__/legacy_platform_service.test.ts.snap b/src/core/public/legacy/__snapshots__/legacy_service.test.ts.snap similarity index 100% rename from src/core/public/legacy_platform/__snapshots__/legacy_platform_service.test.ts.snap rename to src/core/public/legacy/__snapshots__/legacy_service.test.ts.snap diff --git a/src/core/public/legacy_platform/index.ts b/src/core/public/legacy/index.ts similarity index 97% rename from src/core/public/legacy_platform/index.ts rename to src/core/public/legacy/index.ts index 44862dcb4430a..1ea43d8deebbc 100644 --- a/src/core/public/legacy_platform/index.ts +++ b/src/core/public/legacy/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { LegacyPlatformService, LegacyPlatformParams } from './legacy_platform_service'; +export { LegacyPlatformService, LegacyPlatformParams } from './legacy_service'; diff --git a/src/core/public/legacy_platform/legacy_platform_service.test.ts b/src/core/public/legacy/legacy_service.test.ts similarity index 99% rename from src/core/public/legacy_platform/legacy_platform_service.test.ts rename to src/core/public/legacy/legacy_service.test.ts index 7e585869aea24..efe158b926ca5 100644 --- a/src/core/public/legacy_platform/legacy_platform_service.test.ts +++ b/src/core/public/legacy/legacy_service.test.ts @@ -142,7 +142,7 @@ jest.mock('ui/chrome/services/global_nav_state', () => { }; }); -import { LegacyPlatformService } from './legacy_platform_service'; +import { LegacyPlatformService } from './legacy_service'; const fatalErrorsStart = {} as any; const notificationsStart = { diff --git a/src/core/public/legacy_platform/legacy_platform_service.ts b/src/core/public/legacy/legacy_service.ts similarity index 100% rename from src/core/public/legacy_platform/legacy_platform_service.ts rename to src/core/public/legacy/legacy_service.ts diff --git a/src/core/public/ui_settings/__snapshots__/ui_settings_service.test.ts.snap b/src/core/public/ui_settings/__snapshots__/ui_settings_service.test.ts.snap index f165735c41702..bf8f8ba2131a2 100644 --- a/src/core/public/ui_settings/__snapshots__/ui_settings_service.test.ts.snap +++ b/src/core/public/ui_settings/__snapshots__/ui_settings_service.test.ts.snap @@ -12,7 +12,7 @@ exports[`#start constructs UiSettingsClient and UiSettingsApi: UiSettingsApi arg ], "results": Array [ Object { - "isThrow": false, + "type": "return", "value": undefined, }, ], @@ -31,7 +31,7 @@ exports[`#start constructs UiSettingsClient and UiSettingsApi: UiSettingsClient ], "results": Array [ Object { - "isThrow": false, + "type": "return", "value": Object { "loadingCountObservable": true, }, @@ -52,7 +52,7 @@ exports[`#start constructs UiSettingsClient and UiSettingsApi: UiSettingsClient ], "results": Array [ Object { - "isThrow": false, + "type": "return", "value": undefined, }, ], @@ -70,7 +70,7 @@ exports[`#start passes the uiSettings loading count to the loading count api: ht ], "results": Array [ Object { - "isThrow": false, + "type": "return", "value": undefined, }, ], diff --git a/src/core/public/ui_settings/ui_settings_service.test.ts b/src/core/public/ui_settings/ui_settings_service.test.ts index dcb41a94559e4..b21fa4a4d144a 100644 --- a/src/core/public/ui_settings/ui_settings_service.test.ts +++ b/src/core/public/ui_settings/ui_settings_service.test.ts @@ -22,7 +22,7 @@ function mockClass( Class: { new (...args: any[]): T }, setup: (instance: any, args: any[]) => void ) { - const MockClass = jest.fn(function(this: any, ...args: any[]) { + const MockClass = jest.fn(function(this: any, ...args: any[]) { setup(this, args); }); diff --git a/src/core/server/bootstrap.ts b/src/core/server/bootstrap.ts index fcc6d2926dec9..d6b4c441d64f4 100644 --- a/src/core/server/bootstrap.ts +++ b/src/core/server/bootstrap.ts @@ -20,7 +20,7 @@ import chalk from 'chalk'; import { isMaster } from 'cluster'; import { CliArgs, Env, RawConfigService } from './config'; -import { LegacyObjectToConfigAdapter } from './legacy_compat'; +import { LegacyObjectToConfigAdapter } from './legacy'; import { Root } from './root'; interface KibanaFeatures { diff --git a/src/core/server/elasticsearch/cluster_client.test.ts b/src/core/server/elasticsearch/cluster_client.test.ts new file mode 100644 index 0000000000000..5516b19ccbd51 --- /dev/null +++ b/src/core/server/elasticsearch/cluster_client.test.ts @@ -0,0 +1,374 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { ElasticsearchConfig } from './elasticsearch_config'; + +const MockClient = jest.fn(); +jest.mock('elasticsearch', () => ({ + // Jest types don't include `requireActual` right now. + ...(jest as any).requireActual('elasticsearch'), + Client: MockClient, +})); + +const MockScopedClusterClient = jest.fn(); +jest.mock('./scoped_cluster_client', () => ({ + ScopedClusterClient: MockScopedClusterClient, +})); + +const mockParseElasticsearchClientConfig = jest.fn(); +jest.mock('./elasticsearch_client_config', () => ({ + parseElasticsearchClientConfig: mockParseElasticsearchClientConfig, +})); + +import { errors } from 'elasticsearch'; +import { get } from 'lodash'; +import { Logger } from '../logging'; +import { logger } from '../logging/__mocks__'; +import { ClusterClient } from './cluster_client'; + +afterEach(() => jest.clearAllMocks()); + +test('#constructor creates client with parsed config', () => { + const mockEsClientConfig = { apiVersion: 'es-client-master' }; + mockParseElasticsearchClientConfig.mockReturnValue(mockEsClientConfig); + + const mockEsConfig = { apiVersion: 'es-version' } as any; + const mockLogger = logger.get(); + + const clusterClient = new ClusterClient(mockEsConfig, mockLogger); + expect(clusterClient).toBeDefined(); + + expect(mockParseElasticsearchClientConfig).toHaveBeenCalledTimes(1); + expect(mockParseElasticsearchClientConfig).toHaveBeenLastCalledWith(mockEsConfig, mockLogger); + + expect(MockClient).toHaveBeenCalledTimes(1); + expect(MockClient).toHaveBeenCalledWith(mockEsClientConfig); +}); + +describe('#callAsInternalUser', () => { + let mockEsClientInstance: { + close: jest.Mock; + ping: jest.Mock; + security: { authenticate: jest.Mock }; + }; + let clusterClient: ClusterClient; + + beforeEach(() => { + mockEsClientInstance = { + close: jest.fn(), + ping: jest.fn(), + security: { authenticate: jest.fn() }, + }; + MockClient.mockImplementation(() => mockEsClientInstance); + + clusterClient = new ClusterClient({ apiVersion: 'es-version' } as any, logger.get()); + }); + + test('fails if cluster client is closed', async () => { + clusterClient.close(); + + await expect( + clusterClient.callAsInternalUser('ping', {}) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Cluster client cannot be used after it has been closed."` + ); + }); + + test('fails if endpoint is invalid', async () => { + await expect( + clusterClient.callAsInternalUser('pong', {}) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"called with an invalid endpoint: pong"`); + }); + + test('correctly deals with top level endpoint', async () => { + const mockResponse = { data: 'ping' }; + const mockParams = { param: 'ping' }; + mockEsClientInstance.ping.mockImplementation(function mockCall(this: any) { + return Promise.resolve({ + context: this, + response: mockResponse, + }); + }); + + const mockResult = await clusterClient.callAsInternalUser('ping', mockParams); + expect(mockResult.response).toBe(mockResponse); + expect(mockResult.context).toBe(mockEsClientInstance); + expect(mockEsClientInstance.ping).toHaveBeenCalledTimes(1); + expect(mockEsClientInstance.ping).toHaveBeenLastCalledWith(mockParams); + }); + + test('correctly deals with nested endpoint', async () => { + const mockResponse = { data: 'authenticate' }; + const mockParams = { param: 'authenticate' }; + mockEsClientInstance.security.authenticate.mockImplementation(function mockCall(this: any) { + return Promise.resolve({ + context: this, + response: mockResponse, + }); + }); + + const mockResult = await clusterClient.callAsInternalUser('security.authenticate', mockParams); + expect(mockResult.response).toBe(mockResponse); + expect(mockResult.context).toBe(mockEsClientInstance.security); + expect(mockEsClientInstance.security.authenticate).toHaveBeenCalledTimes(1); + expect(mockEsClientInstance.security.authenticate).toHaveBeenLastCalledWith(mockParams); + }); + + test('does not wrap errors if `wrap401Errors` is not set', async () => { + const mockError = { message: 'some error' }; + mockEsClientInstance.ping.mockRejectedValue(mockError); + + await expect( + clusterClient.callAsInternalUser('ping', undefined, { wrap401Errors: false }) + ).rejects.toBe(mockError); + + const mockAuthenticationError = { message: 'authentication error', statusCode: 401 }; + mockEsClientInstance.ping.mockRejectedValue(mockAuthenticationError); + + await expect( + clusterClient.callAsInternalUser('ping', undefined, { wrap401Errors: false }) + ).rejects.toBe(mockAuthenticationError); + }); + + test('wraps only 401 errors by default or when `wrap401Errors` is set', async () => { + const mockError = { message: 'some error' }; + mockEsClientInstance.ping.mockRejectedValue(mockError); + + await expect(clusterClient.callAsInternalUser('ping')).rejects.toBe(mockError); + await expect( + clusterClient.callAsInternalUser('ping', undefined, { wrap401Errors: true }) + ).rejects.toBe(mockError); + + const mockAuthorizationError = { message: 'authentication error', statusCode: 403 }; + mockEsClientInstance.ping.mockRejectedValue(mockAuthorizationError); + + await expect(clusterClient.callAsInternalUser('ping')).rejects.toBe(mockAuthorizationError); + await expect( + clusterClient.callAsInternalUser('ping', undefined, { wrap401Errors: true }) + ).rejects.toBe(mockAuthorizationError); + + const mockAuthenticationError = new (errors.AuthenticationException as any)( + 'Authentication Exception', + { statusCode: 401 } + ); + mockEsClientInstance.ping.mockRejectedValue(mockAuthenticationError); + + await expect(clusterClient.callAsInternalUser('ping')).rejects.toBe(mockAuthenticationError); + await expect( + clusterClient.callAsInternalUser('ping', undefined, { wrap401Errors: true }) + ).rejects.toStrictEqual(mockAuthenticationError); + }); + + test('does not override WWW-Authenticate if returned by Elasticsearch', async () => { + const mockAuthenticationError = new (errors.AuthenticationException as any)( + 'Authentication Exception', + { statusCode: 401 } + ); + + const mockAuthenticationErrorWithHeader = new (errors.AuthenticationException as any)( + 'Authentication Exception', + { + body: { error: { header: { 'WWW-Authenticate': 'some custom header' } } }, + statusCode: 401, + } + ); + mockEsClientInstance.ping + .mockRejectedValueOnce(mockAuthenticationError) + .mockRejectedValueOnce(mockAuthenticationErrorWithHeader); + + await expect(clusterClient.callAsInternalUser('ping')).rejects.toBe(mockAuthenticationError); + expect(get(mockAuthenticationError, 'output.headers.WWW-Authenticate')).toBe( + 'Basic realm="Authorization Required"' + ); + + await expect(clusterClient.callAsInternalUser('ping')).rejects.toBe( + mockAuthenticationErrorWithHeader + ); + expect(get(mockAuthenticationErrorWithHeader, 'output.headers.WWW-Authenticate')).toBe( + 'some custom header' + ); + }); +}); + +describe('#asScoped', () => { + let mockEsClientInstance: { ping: jest.Mock; close: jest.Mock }; + let mockScopedEsClientInstance: { ping: jest.Mock; close: jest.Mock }; + + let clusterClient: ClusterClient; + let mockLogger: Logger; + let mockEsConfig: ElasticsearchConfig; + + beforeEach(() => { + mockEsClientInstance = { ping: jest.fn(), close: jest.fn() }; + mockScopedEsClientInstance = { ping: jest.fn(), close: jest.fn() }; + MockClient.mockImplementationOnce(() => mockEsClientInstance).mockImplementationOnce( + () => mockScopedEsClientInstance + ); + + mockLogger = logger.get(); + mockEsConfig = { + apiVersion: 'es-version', + requestHeadersWhitelist: ['one', 'two'], + } as any; + + clusterClient = new ClusterClient(mockEsConfig, mockLogger); + jest.clearAllMocks(); + }); + + test('creates additional Elasticsearch client only once', () => { + const firstScopedClusterClient = clusterClient.asScoped({ headers: { one: '1' } }); + + expect(firstScopedClusterClient).toBeDefined(); + expect(mockParseElasticsearchClientConfig).toHaveBeenCalledTimes(1); + expect(mockParseElasticsearchClientConfig).toHaveBeenLastCalledWith(mockEsConfig, mockLogger, { + auth: false, + ignoreCertAndKey: true, + }); + + expect(MockClient).toHaveBeenCalledTimes(1); + expect(MockClient).toHaveBeenCalledWith( + mockParseElasticsearchClientConfig.mock.results[0].value + ); + + jest.clearAllMocks(); + + const secondScopedClusterClient = clusterClient.asScoped({ headers: { two: '2' } }); + + expect(secondScopedClusterClient).toBeDefined(); + expect(secondScopedClusterClient).not.toBe(firstScopedClusterClient); + expect(mockParseElasticsearchClientConfig).not.toHaveBeenCalled(); + expect(MockClient).not.toHaveBeenCalled(); + }); + + test('properly configures `ignoreCertAndKey` for various configurations', () => { + // Config without SSL. + clusterClient = new ClusterClient(mockEsConfig, mockLogger); + + mockParseElasticsearchClientConfig.mockClear(); + clusterClient.asScoped({ headers: { one: '1' } }); + + expect(mockParseElasticsearchClientConfig).toHaveBeenCalledTimes(1); + expect(mockParseElasticsearchClientConfig).toHaveBeenLastCalledWith(mockEsConfig, mockLogger, { + auth: false, + ignoreCertAndKey: true, + }); + + // Config ssl.alwaysPresentCertificate === false + mockEsConfig = { ...mockEsConfig, ssl: { alwaysPresentCertificate: false } } as any; + clusterClient = new ClusterClient(mockEsConfig, mockLogger); + + mockParseElasticsearchClientConfig.mockClear(); + clusterClient.asScoped({ headers: { one: '1' } }); + + expect(mockParseElasticsearchClientConfig).toHaveBeenCalledTimes(1); + expect(mockParseElasticsearchClientConfig).toHaveBeenLastCalledWith(mockEsConfig, mockLogger, { + auth: false, + ignoreCertAndKey: true, + }); + + // Config ssl.alwaysPresentCertificate === true + mockEsConfig = { ...mockEsConfig, ssl: { alwaysPresentCertificate: true } } as any; + clusterClient = new ClusterClient(mockEsConfig, mockLogger); + + mockParseElasticsearchClientConfig.mockClear(); + clusterClient.asScoped({ headers: { one: '1' } }); + + expect(mockParseElasticsearchClientConfig).toHaveBeenCalledTimes(1); + expect(mockParseElasticsearchClientConfig).toHaveBeenLastCalledWith(mockEsConfig, mockLogger, { + auth: false, + ignoreCertAndKey: false, + }); + }); + + test('passes only filtered headers to the scoped cluster client', () => { + clusterClient.asScoped({ headers: { zero: '0', one: '1', two: '2', three: '3' } }); + + expect(MockScopedClusterClient).toHaveBeenCalledTimes(1); + expect(MockScopedClusterClient).toHaveBeenCalledWith( + expect.any(Function), + expect.any(Function), + { one: '1', two: '2' } + ); + }); + + test('both scoped and internal API caller fail if cluster client is closed', async () => { + clusterClient.asScoped({ headers: { zero: '0', one: '1', two: '2', three: '3' } }); + + clusterClient.close(); + + const [[internalAPICaller, scopedAPICaller]] = MockScopedClusterClient.mock.calls; + await expect(internalAPICaller('ping')).rejects.toThrowErrorMatchingInlineSnapshot( + `"Cluster client cannot be used after it has been closed."` + ); + + await expect(scopedAPICaller('ping', {})).rejects.toThrowErrorMatchingInlineSnapshot( + `"Cluster client cannot be used after it has been closed."` + ); + }); +}); + +describe('#close', () => { + let mockEsClientInstance: { close: jest.Mock }; + let mockScopedEsClientInstance: { close: jest.Mock }; + + let clusterClient: ClusterClient; + + beforeEach(() => { + mockEsClientInstance = { close: jest.fn() }; + mockScopedEsClientInstance = { close: jest.fn() }; + MockClient.mockImplementationOnce(() => mockEsClientInstance).mockImplementationOnce( + () => mockScopedEsClientInstance + ); + + clusterClient = new ClusterClient( + { apiVersion: 'es-version', requestHeadersWhitelist: [] } as any, + logger.get() + ); + }); + + test('closes underlying Elasticsearch client', () => { + expect(mockEsClientInstance.close).not.toHaveBeenCalled(); + + clusterClient.close(); + expect(mockEsClientInstance.close).toHaveBeenCalledTimes(1); + }); + + test('closes both internal and scoped underlying Elasticsearch clients', () => { + clusterClient.asScoped({ headers: { one: '1' } }); + + expect(mockEsClientInstance.close).not.toHaveBeenCalled(); + expect(mockScopedEsClientInstance.close).not.toHaveBeenCalled(); + + clusterClient.close(); + expect(mockEsClientInstance.close).toHaveBeenCalledTimes(1); + expect(mockScopedEsClientInstance.close).toHaveBeenCalledTimes(1); + }); + + test('does not call close on already closed client', () => { + clusterClient.asScoped({ headers: { one: '1' } }); + + clusterClient.close(); + mockEsClientInstance.close.mockClear(); + mockScopedEsClientInstance.close.mockClear(); + + clusterClient.close(); + expect(mockEsClientInstance.close).not.toHaveBeenCalled(); + expect(mockScopedEsClientInstance.close).not.toHaveBeenCalled(); + }); +}); diff --git a/src/core/server/elasticsearch/cluster_client.ts b/src/core/server/elasticsearch/cluster_client.ts new file mode 100644 index 0000000000000..76d7338983ecf --- /dev/null +++ b/src/core/server/elasticsearch/cluster_client.ts @@ -0,0 +1,196 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 Boom from 'boom'; +import { Client } from 'elasticsearch'; +import { get } from 'lodash'; +import { filterHeaders, Headers } from '../http/router'; +import { Logger } from '../logging'; +import { + ElasticsearchClientConfig, + parseElasticsearchClientConfig, +} from './elasticsearch_client_config'; +import { ScopedClusterClient } from './scoped_cluster_client'; + +/** + * The set of options that defines how API call should be made and result be + * processed. + */ +export interface CallAPIOptions { + /** + * Indicates whether `401 Unauthorized` errors returned from the Elasticsearch API + * should be wrapped into `Boom` error instances with properly set `WWW-Authenticate` + * header that could have been returned by the API itself. If API didn't specify that + * then `Basic realm="Authorization Required"` is used as `WWW-Authenticate`. + */ + wrap401Errors: boolean; +} + +/** + * Calls the Elasticsearch API endpoint with the specified parameters. + * @param client Raw Elasticsearch JS client instance to use. + * @param endpoint Name of the API endpoint to call. + * @param clientParams Parameters that will be directly passed to the + * Elasticsearch JS client. + * @param options Options that affect the way we call the API and process the result. + */ +async function callAPI( + client: Client, + endpoint: string, + clientParams: Record = {}, + options: CallAPIOptions = { wrap401Errors: true } +) { + const clientPath = endpoint.split('.'); + const api: any = get(client, clientPath); + if (!api) { + throw new Error(`called with an invalid endpoint: ${endpoint}`); + } + + const apiContext = clientPath.length === 1 ? client : get(client, clientPath.slice(0, -1)); + try { + return await api.call(apiContext, clientParams); + } catch (err) { + if (!options.wrap401Errors || err.statusCode !== 401) { + throw err; + } + + const boomError = Boom.boomify(err, { statusCode: err.statusCode }); + const wwwAuthHeader: string = get(err, 'body.error.header[WWW-Authenticate]'); + + boomError.output.headers['WWW-Authenticate'] = + wwwAuthHeader || 'Basic realm="Authorization Required"'; + + throw boomError; + } +} + +/** + * Represents an Elasticsearch cluster API client and allows to call API on behalf + * of the internal Kibana user and the actual user that is derived from the request + * headers (via `asScoped(...)`). + */ +export class ClusterClient { + /** + * Raw Elasticsearch JS client that acts on behalf of the Kibana internal user. + */ + private readonly client: Client; + + /** + * Optional raw Elasticsearch JS client that is shared between all the scoped clients created + * from this cluster client. Every API call is attributed by the wh + */ + private scopedClient?: Client; + + /** + * Indicates whether this cluster client (and all internal raw Elasticsearch JS clients) has been closed. + */ + private isClosed = false; + + constructor(private readonly config: ElasticsearchClientConfig, private readonly log: Logger) { + this.client = new Client(parseElasticsearchClientConfig(config, log)); + } + + /** + * Calls specified {@param endpoint} with provided {@param clientParams} on behalf of the + * Kibana internal user. + * @param endpoint String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`. + * @param clientParams A dictionary of parameters that will be passed directly to the Elasticsearch JS client. + * @param options Options that affect the way we call the API and process the result. + */ + public callAsInternalUser = async ( + endpoint: string, + clientParams: Record = {}, + options?: CallAPIOptions + ) => { + this.assertIsNotClosed(); + + return await callAPI(this.client, endpoint, clientParams, options); + }; + + /** + * Closes the cluster client. After that client cannot be used and one should + * create a new client instance to be able to interact with Elasticsearch API. + */ + public close() { + if (this.isClosed) { + return; + } + + this.isClosed = true; + this.client.close(); + + if (this.scopedClient !== undefined) { + this.scopedClient.close(); + } + } + + /** + * Creates an instance of `ScopedClusterClient` based on the configuration the + * current cluster client that exposes additional `callAsCurrentUser` method + * scoped to the provided {@param req}. Consumers shouldn't worry about closing + * scoped client instances, these will be automatically closed as soon as the + * original cluster client isn't needed anymore and closed. + * @param req Request the `ScopedClusterClient` instance will be scoped to. + */ + public asScoped(req: { headers?: Headers } = {}) { + // It'd have been quite expensive to create and configure client for every incoming + // request since it involves parsing of the config, reading of the SSL certificate and + // key files etc. Moreover scoped client needs two Elasticsearch JS clients at the same + // time: one to support `callAsInternalUser` and another one for `callAsCurrentUser`. + // To reduce that overhead we create one scoped client per cluster client and share it + // between all scoped client instances. + if (this.scopedClient === undefined) { + this.scopedClient = new Client( + parseElasticsearchClientConfig(this.config, this.log, { + auth: false, + ignoreCertAndKey: !this.config.ssl || !this.config.ssl.alwaysPresentCertificate, + }) + ); + } + + const headers = req.headers + ? filterHeaders(req.headers, this.config.requestHeadersWhitelist) + : req.headers; + + return new ScopedClusterClient(this.callAsInternalUser, this.callAsCurrentUser, headers); + } + + /** + * Calls specified {@param endpoint} with provided {@param clientParams} on behalf of the + * user initiated request to the Kibana server (via HTTP request headers). + * @param endpoint String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`. + * @param clientParams A dictionary of parameters that will be passed directly to the Elasticsearch JS client. + * @param options Options that affect the way we call the API and process the result. + */ + private callAsCurrentUser = async ( + endpoint: string, + clientParams: Record = {}, + options?: CallAPIOptions + ) => { + this.assertIsNotClosed(); + + return await callAPI(this.scopedClient!, endpoint, clientParams, options); + }; + + private assertIsNotClosed() { + if (this.isClosed) { + throw new Error('Cluster client cannot be used after it has been closed.'); + } + } +} diff --git a/src/core/server/elasticsearch/elasticsearch_client_config.test.ts b/src/core/server/elasticsearch/elasticsearch_client_config.test.ts new file mode 100644 index 0000000000000..9b7dcd37a7482 --- /dev/null +++ b/src/core/server/elasticsearch/elasticsearch_client_config.test.ts @@ -0,0 +1,661 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 mockReadFileSync = jest.fn(); +jest.mock('fs', () => ({ readFileSync: mockReadFileSync })); + +import { duration } from 'moment'; +import { logger } from '../logging/__mocks__'; +import { + ElasticsearchClientConfig, + parseElasticsearchClientConfig, +} from './elasticsearch_client_config'; + +afterEach(() => jest.clearAllMocks()); + +test('parses minimally specified config', () => { + expect( + parseElasticsearchClientConfig( + { + apiVersion: 'master', + customHeaders: { xsrf: 'something' }, + logQueries: false, + sniffOnStart: false, + sniffOnConnectionFault: false, + hosts: ['http://localhost/elasticsearch'], + requestHeadersWhitelist: [], + }, + logger.get() + ) + ).toMatchInlineSnapshot(` +Object { + "apiVersion": "master", + "hosts": Array [ + Object { + "headers": Object { + "xsrf": "something", + }, + "host": "localhost", + "path": "/elasticsearch", + "port": "80", + "protocol": "http:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "sniffOnConnectionFault": false, + "sniffOnStart": false, +} +`); +}); + +test('parses fully specified config', () => { + mockReadFileSync.mockImplementation(path => `content-of-${path}`); + + const elasticsearchConfig: ElasticsearchClientConfig = { + apiVersion: 'v7.0.0', + customHeaders: { xsrf: 'something' }, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: [ + 'http://localhost/elasticsearch', + 'http://domain.com:1234/elasticsearch', + 'https://es.local', + ], + requestHeadersWhitelist: [], + username: 'elastic', + password: 'changeme', + pingTimeout: 12345, + requestTimeout: 54321, + sniffInterval: 11223344, + ssl: { + verificationMode: 'certificate', + certificateAuthorities: ['ca-path-1', 'ca-path-2'], + certificate: 'certificate-path', + key: 'key-path', + keyPassphrase: 'key-pass', + alwaysPresentCertificate: true, + }, + }; + + const elasticsearchClientConfig = parseElasticsearchClientConfig( + elasticsearchConfig, + logger.get() + ); + + // Check that original references aren't used. + for (const host of elasticsearchClientConfig.hosts) { + expect(elasticsearchConfig.customHeaders).not.toBe(host.headers); + } + + expect(elasticsearchConfig.ssl).not.toBe(elasticsearchClientConfig.ssl); + + expect(elasticsearchClientConfig).toMatchInlineSnapshot(` +Object { + "apiVersion": "v7.0.0", + "hosts": Array [ + Object { + "auth": "elastic:changeme", + "headers": Object { + "xsrf": "something", + }, + "host": "localhost", + "path": "/elasticsearch", + "port": "80", + "protocol": "http:", + "query": null, + }, + Object { + "auth": "elastic:changeme", + "headers": Object { + "xsrf": "something", + }, + "host": "domain.com", + "path": "/elasticsearch", + "port": "1234", + "protocol": "http:", + "query": null, + }, + Object { + "auth": "elastic:changeme", + "headers": Object { + "xsrf": "something", + }, + "host": "es.local", + "path": "/", + "port": "443", + "protocol": "https:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "pingTimeout": 12345, + "requestTimeout": 54321, + "sniffInterval": 11223344, + "sniffOnConnectionFault": true, + "sniffOnStart": true, + "ssl": Object { + "ca": Array [ + "content-of-ca-path-1", + "content-of-ca-path-2", + ], + "cert": "content-of-certificate-path", + "checkServerIdentity": [Function], + "key": "content-of-key-path", + "passphrase": "key-pass", + "rejectUnauthorized": true, + }, +} +`); +}); + +test('parses config timeouts of moment.Duration type', () => { + expect( + parseElasticsearchClientConfig( + { + apiVersion: 'master', + customHeaders: { xsrf: 'something' }, + logQueries: false, + sniffOnStart: false, + sniffOnConnectionFault: false, + pingTimeout: duration(100, 'ms'), + requestTimeout: duration(30, 's'), + sniffInterval: duration(1, 'minute'), + hosts: ['http://localhost:9200/elasticsearch'], + requestHeadersWhitelist: [], + }, + logger.get() + ) + ).toMatchInlineSnapshot(` +Object { + "apiVersion": "master", + "hosts": Array [ + Object { + "headers": Object { + "xsrf": "something", + }, + "host": "localhost", + "path": "/elasticsearch", + "port": "9200", + "protocol": "http:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "pingTimeout": 100, + "requestTimeout": 30000, + "sniffInterval": 60000, + "sniffOnConnectionFault": false, + "sniffOnStart": false, +} +`); +}); + +describe('#auth', () => { + test('is not set if #auth = false even if username and password are provided', () => { + expect( + parseElasticsearchClientConfig( + { + apiVersion: 'v7.0.0', + customHeaders: { xsrf: 'something' }, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: ['http://user:password@localhost/elasticsearch', 'https://es.local'], + username: 'elastic', + password: 'changeme', + requestHeadersWhitelist: [], + }, + logger.get(), + { auth: false } + ) + ).toMatchInlineSnapshot(` +Object { + "apiVersion": "v7.0.0", + "hosts": Array [ + Object { + "headers": Object { + "xsrf": "something", + }, + "host": "localhost", + "path": "/elasticsearch", + "port": "80", + "protocol": "http:", + "query": null, + }, + Object { + "headers": Object { + "xsrf": "something", + }, + "host": "es.local", + "path": "/", + "port": "443", + "protocol": "https:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "sniffOnConnectionFault": true, + "sniffOnStart": true, +} +`); + }); + + test('is not set if username is not specified', () => { + expect( + parseElasticsearchClientConfig( + { + apiVersion: 'v7.0.0', + customHeaders: { xsrf: 'something' }, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: ['https://es.local'], + requestHeadersWhitelist: [], + password: 'changeme', + }, + logger.get(), + { auth: true } + ) + ).toMatchInlineSnapshot(` +Object { + "apiVersion": "v7.0.0", + "hosts": Array [ + Object { + "headers": Object { + "xsrf": "something", + }, + "host": "es.local", + "path": "/", + "port": "443", + "protocol": "https:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "sniffOnConnectionFault": true, + "sniffOnStart": true, +} +`); + }); + + test('is not set if password is not specified', () => { + expect( + parseElasticsearchClientConfig( + { + apiVersion: 'v7.0.0', + customHeaders: { xsrf: 'something' }, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: ['https://es.local'], + requestHeadersWhitelist: [], + username: 'elastic', + }, + logger.get(), + { auth: true } + ) + ).toMatchInlineSnapshot(` +Object { + "apiVersion": "v7.0.0", + "hosts": Array [ + Object { + "headers": Object { + "xsrf": "something", + }, + "host": "es.local", + "path": "/", + "port": "443", + "protocol": "https:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "sniffOnConnectionFault": true, + "sniffOnStart": true, +} +`); + }); +}); + +describe('#log', () => { + test('default logger with #logQueries = false', () => { + const parsedConfig = parseElasticsearchClientConfig( + { + apiVersion: 'master', + customHeaders: { xsrf: 'something' }, + logQueries: false, + sniffOnStart: false, + sniffOnConnectionFault: false, + hosts: ['http://localhost/elasticsearch'], + requestHeadersWhitelist: [], + }, + logger.get() + ); + + const esLogger = new parsedConfig.log(); + esLogger.error('some-error'); + esLogger.warning('some-warning'); + esLogger.trace('some-trace'); + esLogger.info('some-info'); + esLogger.debug('some-debug'); + + expect(typeof esLogger.close).toBe('function'); + + expect(logger.mockCollect()).toMatchInlineSnapshot(` +Object { + "debug": Array [], + "error": Array [ + Array [ + "some-error", + ], + ], + "fatal": Array [], + "info": Array [], + "log": Array [], + "trace": Array [], + "warn": Array [ + Array [ + "some-warning", + ], + ], +} +`); + }); + + test('default logger with #logQueries = true', () => { + const parsedConfig = parseElasticsearchClientConfig( + { + apiVersion: 'master', + customHeaders: { xsrf: 'something' }, + logQueries: true, + sniffOnStart: false, + sniffOnConnectionFault: false, + hosts: ['http://localhost/elasticsearch'], + requestHeadersWhitelist: [], + }, + logger.get() + ); + + const esLogger = new parsedConfig.log(); + esLogger.error('some-error'); + esLogger.warning('some-warning'); + + esLogger.trace('METHOD', { path: '/some-path' }, '?query=2', 'unknown', '304'); + + esLogger.info('some-info'); + esLogger.debug('some-debug'); + + expect(typeof esLogger.close).toBe('function'); + + expect(logger.mockCollect()).toMatchInlineSnapshot(` +Object { + "debug": Array [ + Array [ + "304 +METHOD /some-path +?query=2", + Object { + "tags": Array [ + "query", + ], + }, + ], + ], + "error": Array [ + Array [ + "some-error", + ], + ], + "fatal": Array [], + "info": Array [], + "log": Array [], + "trace": Array [], + "warn": Array [ + Array [ + "some-warning", + ], + ], +} +`); + }); + + test('custom logger', () => { + const customLogger = jest.fn(); + + const parsedConfig = parseElasticsearchClientConfig( + { + apiVersion: 'master', + customHeaders: { xsrf: 'something' }, + logQueries: true, + sniffOnStart: false, + sniffOnConnectionFault: false, + hosts: ['http://localhost/elasticsearch'], + requestHeadersWhitelist: [], + log: customLogger, + }, + logger.get() + ); + + expect(parsedConfig.log).toBe(customLogger); + }); +}); + +describe('#ssl', () => { + test('#verificationMode = none', () => { + expect( + parseElasticsearchClientConfig( + { + apiVersion: 'v7.0.0', + customHeaders: {}, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: ['https://es.local'], + requestHeadersWhitelist: [], + ssl: { verificationMode: 'none' }, + }, + logger.get() + ) + ).toMatchInlineSnapshot(` +Object { + "apiVersion": "v7.0.0", + "hosts": Array [ + Object { + "headers": Object {}, + "host": "es.local", + "path": "/", + "port": "443", + "protocol": "https:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "sniffOnConnectionFault": true, + "sniffOnStart": true, + "ssl": Object { + "rejectUnauthorized": false, + }, +} +`); + }); + + test('#verificationMode = certificate', () => { + const clientConfig = parseElasticsearchClientConfig( + { + apiVersion: 'v7.0.0', + customHeaders: {}, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: ['https://es.local'], + requestHeadersWhitelist: [], + ssl: { verificationMode: 'certificate' }, + }, + logger.get() + ); + + // `checkServerIdentity` shouldn't check hostname when verificationMode is certificate. + expect( + clientConfig.ssl!.checkServerIdentity!('right.com', { subject: { CN: 'wrong.com' } } as any) + ).toBeUndefined(); + + expect(clientConfig).toMatchInlineSnapshot(` +Object { + "apiVersion": "v7.0.0", + "hosts": Array [ + Object { + "headers": Object {}, + "host": "es.local", + "path": "/", + "port": "443", + "protocol": "https:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "sniffOnConnectionFault": true, + "sniffOnStart": true, + "ssl": Object { + "checkServerIdentity": [Function], + "rejectUnauthorized": true, + }, +} +`); + }); + + test('#verificationMode = full', () => { + expect( + parseElasticsearchClientConfig( + { + apiVersion: 'v7.0.0', + customHeaders: {}, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: ['https://es.local'], + requestHeadersWhitelist: [], + ssl: { verificationMode: 'full' }, + }, + logger.get() + ) + ).toMatchInlineSnapshot(` +Object { + "apiVersion": "v7.0.0", + "hosts": Array [ + Object { + "headers": Object {}, + "host": "es.local", + "path": "/", + "port": "443", + "protocol": "https:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "sniffOnConnectionFault": true, + "sniffOnStart": true, + "ssl": Object { + "rejectUnauthorized": true, + }, +} +`); + }); + + test('#verificationMode is unknown', () => { + expect(() => + parseElasticsearchClientConfig( + { + apiVersion: 'v7.0.0', + customHeaders: {}, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: ['https://es.local'], + requestHeadersWhitelist: [], + ssl: { verificationMode: 'misspelled' as any }, + }, + logger.get() + ) + ).toThrowErrorMatchingInlineSnapshot(`"Unknown ssl verificationMode: misspelled"`); + }); + + test('#ignoreCertAndKey = true', () => { + mockReadFileSync.mockImplementation(path => `content-of-${path}`); + + expect( + parseElasticsearchClientConfig( + { + apiVersion: 'v7.0.0', + customHeaders: {}, + logQueries: true, + sniffOnStart: true, + sniffOnConnectionFault: true, + hosts: ['https://es.local'], + requestHeadersWhitelist: [], + ssl: { + verificationMode: 'certificate', + certificateAuthorities: ['ca-path'], + certificate: 'certificate-path', + key: 'key-path', + keyPassphrase: 'key-pass', + alwaysPresentCertificate: true, + }, + }, + logger.get(), + { ignoreCertAndKey: true } + ) + ).toMatchInlineSnapshot(` +Object { + "apiVersion": "v7.0.0", + "hosts": Array [ + Object { + "headers": Object {}, + "host": "es.local", + "path": "/", + "port": "443", + "protocol": "https:", + "query": null, + }, + ], + "keepAlive": true, + "log": [Function], + "sniffOnConnectionFault": true, + "sniffOnStart": true, + "ssl": Object { + "ca": Array [ + "content-of-ca-path", + ], + "checkServerIdentity": [Function], + "rejectUnauthorized": true, + }, +} +`); + }); +}); diff --git a/src/core/server/elasticsearch/elasticsearch_client_config.ts b/src/core/server/elasticsearch/elasticsearch_client_config.ts new file mode 100644 index 0000000000000..5df2c32b7d3ba --- /dev/null +++ b/src/core/server/elasticsearch/elasticsearch_client_config.ts @@ -0,0 +1,231 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { ConfigOptions } from 'elasticsearch'; +import { readFileSync } from 'fs'; +import { cloneDeep } from 'lodash'; +import { Duration } from 'moment'; +import { checkServerIdentity } from 'tls'; +import url from 'url'; +import { pick } from '../../utils'; +import { Logger } from '../logging'; +import { ElasticsearchConfig } from './elasticsearch_config'; + +/** + * Config that consumers can pass to the Elasticsearch JS client is complex and includes + * not only entries from standard `elasticsearch.*` yaml config, but also some Elasticsearch JS + * client specific options like `keepAlive` or `plugins` (that eventually will be deprecated). + */ +export type ElasticsearchClientConfig = Pick & + Pick< + ElasticsearchConfig, + | 'apiVersion' + | 'customHeaders' + | 'logQueries' + | 'requestHeadersWhitelist' + | 'sniffOnStart' + | 'sniffOnConnectionFault' + | 'hosts' + | 'username' + | 'password' + > & { + pingTimeout?: ElasticsearchConfig['pingTimeout'] | ConfigOptions['pingTimeout']; + requestTimeout?: ElasticsearchConfig['requestTimeout'] | ConfigOptions['requestTimeout']; + sniffInterval?: ElasticsearchConfig['sniffInterval'] | ConfigOptions['sniffInterval']; + ssl?: Partial; + }; + +/** @internal */ +interface ElasticsearchClientConfigOverrides { + /** + * If set to `true`, username and password from the config won't be used + * to access Elasticsearch API even if these are specified. + */ + auth?: boolean; + + /** + * If set to `true`, `ssl.key` and `ssl.certificate` provided through config won't + * be used to connect to Elasticsearch. + */ + ignoreCertAndKey?: boolean; +} + +// Original `ConfigOptions` defines `ssl: object` so we need something more specific. +/** @internal */ +type ExtendedConfigOptions = ConfigOptions & + Partial<{ + ssl: Partial<{ + rejectUnauthorized: boolean; + checkServerIdentity: typeof checkServerIdentity; + ca: string[]; + cert: string; + key: string; + passphrase: string; + }>; + }>; + +/** @internal */ +export function parseElasticsearchClientConfig( + config: ElasticsearchClientConfig, + log: Logger, + { ignoreCertAndKey = false, auth = true }: ElasticsearchClientConfigOverrides = {} +) { + const esClientConfig: ExtendedConfigOptions = { + keepAlive: true, + ...pick(config, [ + 'apiVersion', + 'sniffOnStart', + 'sniffOnConnectionFault', + 'keepAlive', + 'log', + 'plugins', + ]), + }; + + if (esClientConfig.log == null) { + esClientConfig.log = getLoggerClass(log, config.logQueries); + } + + if (config.pingTimeout != null) { + esClientConfig.pingTimeout = getDurationAsMs(config.pingTimeout); + } + + if (config.requestTimeout != null) { + esClientConfig.requestTimeout = getDurationAsMs(config.requestTimeout); + } + + if (config.sniffInterval) { + esClientConfig.sniffInterval = getDurationAsMs(config.sniffInterval); + } + + if (Array.isArray(config.hosts)) { + const needsAuth = auth !== false && config.username && config.password; + esClientConfig.hosts = config.hosts.map((nodeUrl: string) => { + const uri = url.parse(nodeUrl); + + const httpsURI = uri.protocol === 'https:'; + const httpURI = uri.protocol === 'http:'; + + const host: Record = { + host: uri.hostname, + port: uri.port || (httpsURI && '443') || (httpURI && '80'), + protocol: uri.protocol, + path: uri.pathname, + query: uri.query, + headers: config.customHeaders, + }; + + if (needsAuth) { + host.auth = `${config.username}:${config.password}`; + } + + return host; + }); + } + + if (config.ssl === undefined) { + return cloneDeep(esClientConfig); + } + + esClientConfig.ssl = {}; + + const verificationMode = config.ssl.verificationMode; + switch (verificationMode) { + case 'none': + esClientConfig.ssl.rejectUnauthorized = false; + break; + case 'certificate': + esClientConfig.ssl.rejectUnauthorized = true; + + // by default, NodeJS is checking the server identify + esClientConfig.ssl.checkServerIdentity = () => undefined; + break; + case 'full': + esClientConfig.ssl.rejectUnauthorized = true; + break; + default: + throw new Error(`Unknown ssl verificationMode: ${verificationMode}`); + } + + const readFile = (file: string) => readFileSync(file, 'utf8'); + if ( + config.ssl.certificateAuthorities !== undefined && + config.ssl.certificateAuthorities.length > 0 + ) { + esClientConfig.ssl.ca = config.ssl.certificateAuthorities.map(readFile); + } + + // Add client certificate and key if required by elasticsearch + if (!ignoreCertAndKey && config.ssl.certificate && config.ssl.key) { + esClientConfig.ssl.cert = readFile(config.ssl.certificate); + esClientConfig.ssl.key = readFile(config.ssl.key); + esClientConfig.ssl.passphrase = config.ssl.keyPassphrase; + } + + // Elasticsearch JS client mutates config object, so all properties that are + // usually passed by reference should be cloned to avoid any side effects. + return cloneDeep(esClientConfig); +} + +function getDurationAsMs(duration: number | Duration) { + if (typeof duration === 'number') { + return duration; + } + + return duration.asMilliseconds(); +} + +function getLoggerClass(log: Logger, logQueries = false) { + return class ElasticsearchClientLogging { + public error(err: string | Error) { + log.error(err); + } + + public warning(message: string) { + log.warn(message); + } + + public trace( + method: string, + options: { path: string }, + query: string, + _: unknown, + statusCode: string + ) { + if (logQueries) { + log.debug(`${statusCode}\n${method} ${options.path}\n${query ? query.trim() : ''}`, { + tags: ['query'], + }); + } + } + + // elasticsearch-js expects the following functions to exist + public info() { + // noop + } + + public debug() { + // noop + } + + public close() { + // noop + } + }; +} diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.ts b/src/core/server/elasticsearch/elasticsearch_config.test.ts new file mode 100644 index 0000000000000..b97370eafa040 --- /dev/null +++ b/src/core/server/elasticsearch/elasticsearch_config.test.ts @@ -0,0 +1,108 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { ElasticsearchConfig } from './elasticsearch_config'; + +test('set correct defaults', () => { + const config = new ElasticsearchConfig(ElasticsearchConfig.schema.validate({})); + expect(config).toMatchInlineSnapshot(` +ElasticsearchConfig { + "apiVersion": "master", + "customHeaders": Object {}, + "healthCheckDelay": "PT2.5S", + "hosts": Array [ + "http://localhost:9200", + ], + "logQueries": false, + "password": undefined, + "pingTimeout": "PT30S", + "requestHeadersWhitelist": Array [ + "authorization", + ], + "requestTimeout": "PT30S", + "shardTimeout": "PT30S", + "sniffInterval": false, + "sniffOnConnectionFault": false, + "sniffOnStart": false, + "ssl": Object { + "alwaysPresentCertificate": true, + "certificateAuthorities": undefined, + "verificationMode": "full", + }, + "username": undefined, +} +`); +}); + +test('#hosts accepts both string and array of strings', () => { + let config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ hosts: 'http://some.host:1234' }) + ); + expect(config.hosts).toEqual(['http://some.host:1234']); + + config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ hosts: ['http://some.host:1234'] }) + ); + expect(config.hosts).toEqual(['http://some.host:1234']); + + config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ + hosts: ['http://some.host:1234', 'https://some.another.host'], + }) + ); + expect(config.hosts).toEqual(['http://some.host:1234', 'https://some.another.host']); +}); + +test('#requestHeadersWhitelist accepts both string and array of strings', () => { + let config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ requestHeadersWhitelist: 'token' }) + ); + expect(config.requestHeadersWhitelist).toEqual(['token']); + + config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ requestHeadersWhitelist: ['token'] }) + ); + expect(config.requestHeadersWhitelist).toEqual(['token']); + + config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ + requestHeadersWhitelist: ['token', 'X-Forwarded-Proto'], + }) + ); + expect(config.requestHeadersWhitelist).toEqual(['token', 'X-Forwarded-Proto']); +}); + +test('#ssl.certificateAuthorities accepts both string and array of strings', () => { + let config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ ssl: { certificateAuthorities: 'some-path' } }) + ); + expect(config.ssl.certificateAuthorities).toEqual(['some-path']); + + config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ ssl: { certificateAuthorities: ['some-path'] } }) + ); + expect(config.ssl.certificateAuthorities).toEqual(['some-path']); + + config = new ElasticsearchConfig( + ElasticsearchConfig.schema.validate({ + ssl: { certificateAuthorities: ['some-path', 'another-path'] }, + }) + ); + expect(config.ssl.certificateAuthorities).toEqual(['some-path', 'another-path']); +}); diff --git a/src/core/server/elasticsearch/elasticsearch_config.ts b/src/core/server/elasticsearch/elasticsearch_config.ts new file mode 100644 index 0000000000000..e456d7a74e10b --- /dev/null +++ b/src/core/server/elasticsearch/elasticsearch_config.ts @@ -0,0 +1,188 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { schema, TypeOf } from '@kbn/config-schema'; +import { Duration } from 'moment'; + +const hostURISchema = schema.uri({ scheme: ['http', 'https'] }); + +export const DEFAULT_API_VERSION = 'master'; + +const configSchema = schema.object({ + sniffOnStart: schema.boolean({ defaultValue: false }), + sniffInterval: schema.oneOf([schema.duration(), schema.literal(false)], { defaultValue: false }), + sniffOnConnectionFault: schema.boolean({ defaultValue: false }), + hosts: schema.oneOf([hostURISchema, schema.arrayOf(hostURISchema, { minSize: 1 })], { + defaultValue: 'http://localhost:9200', + }), + preserveHost: schema.boolean({ defaultValue: true }), + username: schema.maybe(schema.string()), + password: schema.maybe(schema.string()), + requestHeadersWhitelist: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { + defaultValue: ['authorization'], + }), + customHeaders: schema.recordOf(schema.string(), schema.string(), { defaultValue: {} }), + shardTimeout: schema.duration({ defaultValue: '30s' }), + requestTimeout: schema.duration({ defaultValue: '30s' }), + pingTimeout: schema.duration({ defaultValue: schema.siblingRef('requestTimeout') }), + startupTimeout: schema.duration({ defaultValue: '5s' }), + logQueries: schema.boolean({ defaultValue: false }), + ssl: schema.object({ + verificationMode: schema.oneOf( + [schema.literal('none'), schema.literal('certificate'), schema.literal('full')], + { defaultValue: 'full' } + ), + certificateAuthorities: schema.maybe( + schema.oneOf([schema.string(), schema.arrayOf(schema.string(), { minSize: 1 })]) + ), + certificate: schema.maybe(schema.string()), + key: schema.maybe(schema.string()), + keyPassphrase: schema.maybe(schema.string()), + alwaysPresentCertificate: schema.boolean({ defaultValue: true }), + }), + apiVersion: schema.string({ defaultValue: DEFAULT_API_VERSION }), + healthCheck: schema.object({ delay: schema.duration({ defaultValue: 2500 }) }), +}); + +type SslConfigSchema = TypeOf['ssl']; + +export class ElasticsearchConfig { + public static schema = configSchema; + + /** + * The interval between health check requests Kibana sends to the Elasticsearch. + */ + public readonly healthCheckDelay: Duration; + + /** + * Version of the Elasticsearch (6.7, 7.1 or `master`) client will be connecting to. + */ + public readonly apiVersion: string; + + /** + * Specifies whether all queries to the client should be logged (status code, + * method, query etc.). + */ + public readonly logQueries: boolean; + + /** + * Hosts that the client will connect to. If sniffing is enabled, this list will + * be used as seeds to discover the rest of your cluster. + */ + public readonly hosts: string[]; + + /** + * List of Kibana client-side headers to send to Elasticsearch when request + * scoped cluster client is used. If this is an empty array then *no* client-side + * will be sent. + */ + public readonly requestHeadersWhitelist: string[]; + + /** + * Timeout after which PING HTTP request will be aborted and retried. + */ + public readonly pingTimeout: Duration; + + /** + * Timeout after which HTTP request will be aborted and retried. + */ + public readonly requestTimeout: Duration; + + /** + * Timeout for Elasticsearch to wait for responses from shards. Set to 0 to disable. + */ + public readonly shardTimeout: Duration; + + /** + * Specifies whether the client should attempt to detect the rest of the cluster + * when it is first instantiated. + */ + public readonly sniffOnStart: boolean; + + /** + * Interval to perform a sniff operation and make sure the list of nodes is complete. + * If `false` then sniffing is disabled. + */ + public readonly sniffInterval: false | Duration; + + /** + * Specifies whether the client should immediately sniff for a more current list + * of nodes when a connection dies. + */ + public readonly sniffOnConnectionFault: boolean; + + /** + * If Elasticsearch is protected with basic authentication, this setting provides + * the username that the Kibana server uses to perform its administrative functions. + */ + public readonly username?: string; + + /** + * If Elasticsearch is protected with basic authentication, this setting provides + * the password that the Kibana server uses to perform its administrative functions. + */ + public readonly password?: string; + + /** + * Set of settings configure SSL connection between Kibana and Elasticsearch that + * are required when `xpack.ssl.verification_mode` in Elasticsearch is set to + * either `certificate` or `full`. + */ + public readonly ssl: Pick< + SslConfigSchema, + Exclude + > & { certificateAuthorities?: string[] }; + + /** + * Header names and values to send to Elasticsearch with every request. These + * headers cannot be overwritten by client-side headers and aren't affected by + * `requestHeadersWhitelist` configuration. + */ + public readonly customHeaders: TypeOf['customHeaders']; + + constructor(config: TypeOf) { + this.apiVersion = config.apiVersion; + this.logQueries = config.logQueries; + this.hosts = Array.isArray(config.hosts) ? config.hosts : [config.hosts]; + this.requestHeadersWhitelist = Array.isArray(config.requestHeadersWhitelist) + ? config.requestHeadersWhitelist + : [config.requestHeadersWhitelist]; + this.pingTimeout = config.pingTimeout; + this.requestTimeout = config.requestTimeout; + this.shardTimeout = config.shardTimeout; + this.sniffOnStart = config.sniffOnStart; + this.sniffOnConnectionFault = config.sniffOnConnectionFault; + this.sniffInterval = config.sniffInterval; + this.healthCheckDelay = config.healthCheck.delay; + this.username = config.username; + this.password = config.password; + this.customHeaders = config.customHeaders; + + const certificateAuthorities = Array.isArray(config.ssl.certificateAuthorities) + ? config.ssl.certificateAuthorities + : typeof config.ssl.certificateAuthorities === 'string' + ? [config.ssl.certificateAuthorities] + : undefined; + + this.ssl = { + ...config.ssl, + certificateAuthorities, + }; + } +} diff --git a/src/core/server/elasticsearch/elasticsearch_service.test.ts b/src/core/server/elasticsearch/elasticsearch_service.test.ts new file mode 100644 index 0000000000000..a7559cc2687f7 --- /dev/null +++ b/src/core/server/elasticsearch/elasticsearch_service.test.ts @@ -0,0 +1,133 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { first } from 'rxjs/operators'; + +const MockClusterClient = jest.fn(); +jest.mock('./cluster_client', () => ({ ClusterClient: MockClusterClient })); + +import { BehaviorSubject, combineLatest } from 'rxjs'; +import { CoreContext } from '../../types'; +import { Config, ConfigService, Env, ObjectToConfigAdapter } from '../config'; +import { getEnvOptions } from '../config/__mocks__/env'; +import { logger } from '../logging/__mocks__'; +import { ElasticsearchConfig } from './elasticsearch_config'; +import { ElasticsearchService } from './elasticsearch_service'; + +let elasticsearchService: ElasticsearchService; +let configService: ConfigService; +let env: Env; +let coreContext: CoreContext; +beforeEach(() => { + env = Env.createDefault(getEnvOptions()); + + configService = new ConfigService( + new BehaviorSubject( + new ObjectToConfigAdapter({ + elasticsearch: { hosts: ['http://1.2.3.4'], username: 'jest' }, + }) + ), + env, + logger + ); + + coreContext = { env, logger, configService }; + elasticsearchService = new ElasticsearchService(coreContext); +}); + +afterEach(() => jest.clearAllMocks()); + +describe('#start', () => { + test('returns legacy Elasticsearch config as a part of the contract', async () => { + const startContract = await elasticsearchService.start(); + + await expect(startContract.legacy.config$.pipe(first()).toPromise()).resolves.toBeInstanceOf( + ElasticsearchConfig + ); + }); + + test('returns data and admin client observables as a part of the contract', async () => { + const mockAdminClusterClientInstance = { close: jest.fn() }; + const mockDataClusterClientInstance = { close: jest.fn() }; + MockClusterClient.mockImplementationOnce( + () => mockAdminClusterClientInstance + ).mockImplementationOnce(() => mockDataClusterClientInstance); + + const startContract = await elasticsearchService.start(); + + const [esConfig, adminClient, dataClient] = await combineLatest( + startContract.legacy.config$, + startContract.adminClient$, + startContract.dataClient$ + ) + .pipe(first()) + .toPromise(); + + expect(adminClient).toBe(mockAdminClusterClientInstance); + expect(dataClient).toBe(mockDataClusterClientInstance); + + expect(MockClusterClient).toHaveBeenCalledTimes(2); + expect(MockClusterClient).toHaveBeenNthCalledWith( + 1, + esConfig, + expect.objectContaining({ context: ['elasticsearch', 'admin'] }) + ); + expect(MockClusterClient).toHaveBeenNthCalledWith( + 2, + esConfig, + expect.objectContaining({ context: ['elasticsearch', 'data'] }) + ); + + expect(mockAdminClusterClientInstance.close).not.toHaveBeenCalled(); + expect(mockDataClusterClientInstance.close).not.toHaveBeenCalled(); + }); + + test('returns `createClient` as a part of the contract', async () => { + const startContract = await elasticsearchService.start(); + + const mockClusterClientInstance = { close: jest.fn() }; + MockClusterClient.mockImplementation(() => mockClusterClientInstance); + + const mockConfig = { logQueries: true }; + const clusterClient = startContract.createClient('some-custom-type', mockConfig as any); + + expect(clusterClient).toBe(mockClusterClientInstance); + + expect(MockClusterClient).toHaveBeenCalledWith( + mockConfig, + expect.objectContaining({ context: ['elasticsearch', 'some-custom-type'] }) + ); + }); +}); + +describe('#stop', () => { + test('stops both admin and data clients', async () => { + const mockAdminClusterClientInstance = { close: jest.fn() }; + const mockDataClusterClientInstance = { close: jest.fn() }; + MockClusterClient.mockImplementationOnce( + () => mockAdminClusterClientInstance + ).mockImplementationOnce(() => mockDataClusterClientInstance); + + await elasticsearchService.start(); + await elasticsearchService.stop(); + + expect(mockAdminClusterClientInstance.close).toHaveBeenCalledTimes(1); + expect(mockDataClusterClientInstance.close).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/core/server/elasticsearch/elasticsearch_service.ts b/src/core/server/elasticsearch/elasticsearch_service.ts new file mode 100644 index 0000000000000..7a1b7e717e49b --- /dev/null +++ b/src/core/server/elasticsearch/elasticsearch_service.ts @@ -0,0 +1,118 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { ConnectableObservable, Observable, Subscription } from 'rxjs'; +import { filter, map, publishReplay, switchMap } from 'rxjs/operators'; +import { CoreContext, CoreService } from '../../types'; +import { Logger } from '../logging'; +import { ClusterClient } from './cluster_client'; +import { ElasticsearchClientConfig } from './elasticsearch_client_config'; +import { ElasticsearchConfig } from './elasticsearch_config'; + +interface CoreClusterClients { + config: ElasticsearchConfig; + adminClient: ClusterClient; + dataClient: ClusterClient; +} + +export interface ElasticsearchServiceStart { + // Required for the BWC with the legacy Kibana only. + readonly legacy: { + readonly config$: Observable; + }; + + readonly createClient: (type: string, config: ElasticsearchClientConfig) => ClusterClient; + readonly adminClient$: Observable; + readonly dataClient$: Observable; +} + +/** @internal */ +export class ElasticsearchService implements CoreService { + private readonly log: Logger; + private subscription?: Subscription; + + constructor(private readonly coreContext: CoreContext) { + this.log = coreContext.logger.get('elasticsearch-service'); + } + + public async start(): Promise { + this.log.debug('Starting elasticsearch service'); + + const clients$ = this.coreContext.configService + .atPath('elasticsearch', ElasticsearchConfig) + .pipe( + filter(() => { + if (this.subscription !== undefined) { + this.log.error('Clients cannot be changed after they are created'); + return false; + } + + return true; + }), + switchMap( + config => + new Observable(subscriber => { + this.log.debug(`Creating elasticsearch clients`); + + const coreClients = { + config, + adminClient: this.createClusterClient('admin', config), + dataClient: this.createClusterClient('data', config), + }; + + subscriber.next(coreClients); + + return () => { + this.log.debug(`Closing elasticsearch clients`); + + coreClients.adminClient.close(); + coreClients.dataClient.close(); + }; + }) + ), + publishReplay(1) + ) as ConnectableObservable; + + this.subscription = clients$.connect(); + + return { + legacy: { config$: clients$.pipe(map(clients => clients.config)) }, + + adminClient$: clients$.pipe(map(clients => clients.adminClient)), + dataClient$: clients$.pipe(map(clients => clients.dataClient)), + + createClient: (type: string, clientConfig: ElasticsearchClientConfig) => { + return this.createClusterClient(type, clientConfig); + }, + }; + } + + public async stop() { + this.log.debug('Stopping elasticsearch service'); + + if (this.subscription !== undefined) { + this.subscription.unsubscribe(); + this.subscription = undefined; + } + } + + private createClusterClient(type: string, config: ElasticsearchClientConfig) { + return new ClusterClient(config, this.coreContext.logger.get('elasticsearch', type)); + } +} diff --git a/src/legacy/core_plugins/elasticsearch/lib/filter_headers.js b/src/core/server/elasticsearch/index.ts similarity index 64% rename from src/legacy/core_plugins/elasticsearch/lib/filter_headers.js rename to src/core/server/elasticsearch/index.ts index 2361788cf0cb7..47242678ec736 100644 --- a/src/legacy/core_plugins/elasticsearch/lib/filter_headers.js +++ b/src/core/server/elasticsearch/index.ts @@ -17,19 +17,17 @@ * under the License. */ -import _ from 'lodash'; +export { ElasticsearchServiceStart } from './elasticsearch_service'; +export { CallAPIOptions, ClusterClient } from './cluster_client'; -export default function (originalHeaders, headersToKeep) { - const normalizeHeader = function (header) { - if (!header) { - return ''; - } - header = header.toString(); - return header.trim().toLowerCase(); - }; +import { CoreContext } from '../../types'; +import { ElasticsearchService } from './elasticsearch_service'; - // Normalize list of headers we want to allow in upstream request - const headersToKeepNormalized = headersToKeep.map(normalizeHeader); +/** @internal */ +export class ElasticsearchModule { + public readonly service: ElasticsearchService; - return _.pick(originalHeaders, headersToKeepNormalized); + constructor(coreContext: CoreContext) { + this.service = new ElasticsearchService(coreContext); + } } diff --git a/src/core/server/elasticsearch/scoped_cluster_client.test.ts b/src/core/server/elasticsearch/scoped_cluster_client.test.ts new file mode 100644 index 0000000000000..6879d86ce2cdf --- /dev/null +++ b/src/core/server/elasticsearch/scoped_cluster_client.test.ts @@ -0,0 +1,169 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { ScopedClusterClient } from './scoped_cluster_client'; + +let internalAPICaller: jest.Mock; +let scopedAPICaller: jest.Mock; +let clusterClient: ScopedClusterClient; +beforeEach(() => { + internalAPICaller = jest.fn(); + scopedAPICaller = jest.fn(); + clusterClient = new ScopedClusterClient(internalAPICaller, scopedAPICaller, { one: '1' }); +}); + +afterEach(() => jest.clearAllMocks()); + +describe('#callAsInternalUser', () => { + test('properly forwards arguments to the API caller and results back from it', async () => { + const mockResponse = { data: 'response' }; + internalAPICaller.mockResolvedValue(mockResponse); + + await expect(clusterClient.callAsInternalUser('ping')).resolves.toBe(mockResponse); + expect(internalAPICaller).toHaveBeenCalledTimes(1); + expect(internalAPICaller).toHaveBeenCalledWith('ping', {}, undefined); + internalAPICaller.mockClear(); + + await expect( + clusterClient.callAsInternalUser('security.authenticate', { some: 'some' }) + ).resolves.toBe(mockResponse); + expect(internalAPICaller).toHaveBeenCalledTimes(1); + expect(internalAPICaller).toHaveBeenCalledWith( + 'security.authenticate', + { some: 'some' }, + undefined + ); + internalAPICaller.mockClear(); + + await expect( + clusterClient.callAsInternalUser('ping', undefined, { wrap401Errors: true }) + ).resolves.toBe(mockResponse); + expect(internalAPICaller).toHaveBeenCalledTimes(1); + expect(internalAPICaller).toHaveBeenCalledWith('ping', {}, { wrap401Errors: true }); + internalAPICaller.mockClear(); + + await expect( + clusterClient.callAsInternalUser( + 'security.authenticate', + { some: 'some' }, + { wrap401Errors: true } + ) + ).resolves.toBe(mockResponse); + expect(internalAPICaller).toHaveBeenCalledTimes(1); + expect(internalAPICaller).toHaveBeenCalledWith( + 'security.authenticate', + { some: 'some' }, + { wrap401Errors: true } + ); + + expect(scopedAPICaller).not.toHaveBeenCalled(); + }); + + test('properly forwards errors returned by the API caller', async () => { + const mockErrorResponse = new Error('some-error'); + internalAPICaller.mockRejectedValue(mockErrorResponse); + + await expect(clusterClient.callAsInternalUser('ping')).rejects.toBe(mockErrorResponse); + + expect(scopedAPICaller).not.toHaveBeenCalled(); + }); +}); + +describe('#callAsCurrentUser', () => { + test('properly forwards arguments to the API caller and results back from it', async () => { + const mockResponse = { data: 'response' }; + scopedAPICaller.mockResolvedValue(mockResponse); + + await expect(clusterClient.callAsCurrentUser('ping')).resolves.toBe(mockResponse); + expect(scopedAPICaller).toHaveBeenCalledTimes(1); + expect(scopedAPICaller).toHaveBeenCalledWith('ping', { headers: { one: '1' } }, undefined); + scopedAPICaller.mockClear(); + + await expect( + clusterClient.callAsCurrentUser('security.authenticate', { some: 'some' }) + ).resolves.toBe(mockResponse); + expect(scopedAPICaller).toHaveBeenCalledTimes(1); + expect(scopedAPICaller).toHaveBeenCalledWith( + 'security.authenticate', + { some: 'some', headers: { one: '1' } }, + undefined + ); + scopedAPICaller.mockClear(); + + await expect( + clusterClient.callAsCurrentUser('ping', undefined, { wrap401Errors: true }) + ).resolves.toBe(mockResponse); + expect(scopedAPICaller).toHaveBeenCalledTimes(1); + expect(scopedAPICaller).toHaveBeenCalledWith( + 'ping', + { headers: { one: '1' } }, + { wrap401Errors: true } + ); + scopedAPICaller.mockClear(); + + await expect( + clusterClient.callAsCurrentUser( + 'security.authenticate', + { some: 'some', headers: { one: '1' } }, + { wrap401Errors: true } + ) + ).resolves.toBe(mockResponse); + expect(scopedAPICaller).toHaveBeenCalledTimes(1); + expect(scopedAPICaller).toHaveBeenCalledWith( + 'security.authenticate', + { some: 'some', headers: { one: '1' } }, + { wrap401Errors: true } + ); + + expect(internalAPICaller).not.toHaveBeenCalled(); + }); + + test('properly forwards errors returned by the API caller', async () => { + const mockErrorResponse = new Error('some-error'); + scopedAPICaller.mockRejectedValue(mockErrorResponse); + + await expect(clusterClient.callAsCurrentUser('ping')).rejects.toBe(mockErrorResponse); + + expect(internalAPICaller).not.toHaveBeenCalled(); + }); + + test('does not attach headers to the client params if they are not available', async () => { + const mockResponse = { data: 'response' }; + scopedAPICaller.mockResolvedValue(mockResponse); + + const clusterClientWithoutHeaders = new ScopedClusterClient(internalAPICaller, scopedAPICaller); + + await expect(clusterClientWithoutHeaders.callAsCurrentUser('ping')).resolves.toBe(mockResponse); + expect(scopedAPICaller).toHaveBeenCalledTimes(1); + expect(scopedAPICaller).toHaveBeenCalledWith('ping', {}, undefined); + scopedAPICaller.mockClear(); + + await expect( + clusterClientWithoutHeaders.callAsCurrentUser('security.authenticate', { some: 'some' }) + ).resolves.toBe(mockResponse); + expect(scopedAPICaller).toHaveBeenCalledTimes(1); + expect(scopedAPICaller).toHaveBeenCalledWith( + 'security.authenticate', + { some: 'some' }, + undefined + ); + + expect(internalAPICaller).not.toHaveBeenCalled(); + }); +}); diff --git a/src/core/server/elasticsearch/scoped_cluster_client.ts b/src/core/server/elasticsearch/scoped_cluster_client.ts new file mode 100644 index 0000000000000..0d0922d80c996 --- /dev/null +++ b/src/core/server/elasticsearch/scoped_cluster_client.ts @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { Headers } from '../http/router'; +import { CallAPIOptions } from './cluster_client'; + +type APICaller = ( + endpoint: string, + clientParams: Record, + options?: CallAPIOptions +) => Promise; + +/** + * Serves the same purpose as "normal" `ClusterClient` but exposes additional + * `callAsCurrentUser` method that doesn't use credentials of the Kibana internal + * user (as `callAsInternalUser` does) to request Elasticsearch API, but rather + * passes HTTP headers extracted from the current user request to the API + */ +export class ScopedClusterClient { + constructor( + private readonly internalAPICaller: APICaller, + private readonly scopedAPICaller: APICaller, + private readonly headers?: Headers + ) {} + + /** + * Calls specified {@param endpoint} with provided {@param clientParams} on behalf of the + * Kibana internal user. + * @param endpoint String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`. + * @param clientParams A dictionary of parameters that will be passed directly to the Elasticsearch JS client. + * @param options Options that affect the way we call the API and process the result. + */ + public callAsInternalUser( + endpoint: string, + clientParams: Record = {}, + options?: CallAPIOptions + ) { + return this.internalAPICaller(endpoint, clientParams, options); + } + + /** + * Calls specified {@param endpoint} with provided {@param clientParams} on behalf of the + * user initiated request to the Kibana server (via HTTP request headers). + * @param endpoint String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`. + * @param clientParams A dictionary of parameters that will be passed directly to the Elasticsearch JS client. + * @param options Options that affect the way we call the API and process the result. + */ + public callAsCurrentUser( + endpoint: string, + clientParams: Record = {}, + options?: CallAPIOptions + ) { + if (this.headers !== undefined) { + clientParams.headers = this.headers; + } + + return this.scopedAPICaller(endpoint, clientParams, options); + } +} diff --git a/src/core/server/http/https_redirect_server.test.ts b/src/core/server/http/https_redirect_server.test.ts index a9fd8ec12e155..c9f7fab20c70c 100644 --- a/src/core/server/http/https_redirect_server.test.ts +++ b/src/core/server/http/https_redirect_server.test.ts @@ -91,8 +91,7 @@ test('throws if [redirectHttpFromPort] is in use', async () => { } as HttpConfig) ).rejects.toMatchSnapshot(); - // Workaround for https://github.com/DefinitelyTyped/DefinitelyTyped/issues/17605. - (mockListen as any).mockRestore(); + mockListen.mockRestore(); }); test('forwards http requests to https', async () => { diff --git a/src/core/server/http/router/headers.ts b/src/core/server/http/router/headers.ts index d5a3de1ff452d..bed1a65c07890 100644 --- a/src/core/server/http/router/headers.ts +++ b/src/core/server/http/router/headers.ts @@ -19,9 +19,7 @@ import { pick } from '../../../utils'; -export interface Headers { - [key: string]: string | string[] | undefined; -} +export type Headers = Record; const normalizeHeaderField = (field: string) => field.trim().toLowerCase(); diff --git a/src/core/server/http/router/index.ts b/src/core/server/http/router/index.ts index ceec1d4c42649..7be20cccd589a 100644 --- a/src/core/server/http/router/index.ts +++ b/src/core/server/http/router/index.ts @@ -17,5 +17,6 @@ * under the License. */ +export { Headers, filterHeaders } from './headers'; export { Router } from './router'; export { KibanaRequest } from './request'; diff --git a/src/core/server/index.test.ts b/src/core/server/index.test.ts index bd00deea55d44..3ba25a83bb39b 100644 --- a/src/core/server/index.test.ts +++ b/src/core/server/index.test.ts @@ -27,8 +27,13 @@ jest.mock('./plugins/plugins_service', () => ({ PluginsService: jest.fn(() => mockPluginsService), })); +const mockElasticsearchService = { start: jest.fn(), stop: jest.fn() }; +jest.mock('./elasticsearch/elasticsearch_service', () => ({ + ElasticsearchService: jest.fn(() => mockElasticsearchService), +})); + const mockLegacyService = { start: jest.fn(), stop: jest.fn() }; -jest.mock('./legacy_compat/legacy_service', () => ({ +jest.mock('./legacy/legacy_service', () => ({ LegacyService: jest.fn(() => mockLegacyService), })); @@ -50,6 +55,8 @@ afterEach(() => { mockConfigService.atPath.mockReset(); mockHttpService.start.mockReset(); mockHttpService.stop.mockReset(); + mockElasticsearchService.start.mockReset(); + mockElasticsearchService.stop.mockReset(); mockPluginsService.start.mockReset(); mockPluginsService.stop.mockReset(); mockLegacyService.start.mockReset(); @@ -60,21 +67,32 @@ test('starts services on "start"', async () => { const mockHttpServiceStart = { something: true }; mockHttpService.start.mockReturnValue(Promise.resolve(mockHttpServiceStart)); + const mockElasticsearchServiceStart = { adminClient$: {} }; + mockElasticsearchService.start.mockResolvedValue(mockElasticsearchServiceStart); + const mockPluginsServiceStart = new Map([['some-plugin', 'some-value']]); mockPluginsService.start.mockReturnValue(Promise.resolve(mockPluginsServiceStart)); const server = new Server(mockConfigService as any, logger, env); expect(mockHttpService.start).not.toHaveBeenCalled(); + expect(mockElasticsearchService.start).not.toHaveBeenCalled(); expect(mockPluginsService.start).not.toHaveBeenCalled(); expect(mockLegacyService.start).not.toHaveBeenCalled(); await server.start(); expect(mockHttpService.start).toHaveBeenCalledTimes(1); + expect(mockElasticsearchService.start).toHaveBeenCalledTimes(1); + expect(mockPluginsService.start).toHaveBeenCalledTimes(1); + expect(mockPluginsService.start).toHaveBeenCalledWith({ + elasticsearch: mockElasticsearchServiceStart, + }); + expect(mockLegacyService.start).toHaveBeenCalledTimes(1); expect(mockLegacyService.start).toHaveBeenCalledWith({ + elasticsearch: mockElasticsearchServiceStart, http: mockHttpServiceStart, plugins: mockPluginsServiceStart, }); @@ -127,12 +145,14 @@ test('stops services on "stop"', async () => { await server.start(); expect(mockHttpService.stop).not.toHaveBeenCalled(); + expect(mockElasticsearchService.stop).not.toHaveBeenCalled(); expect(mockPluginsService.stop).not.toHaveBeenCalled(); expect(mockLegacyService.stop).not.toHaveBeenCalled(); await server.stop(); expect(mockHttpService.stop).toHaveBeenCalledTimes(1); + expect(mockElasticsearchService.stop).toHaveBeenCalledTimes(1); expect(mockPluginsService.stop).toHaveBeenCalledTimes(1); expect(mockLegacyService.stop).toHaveBeenCalledTimes(1); }); diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 552c6b977b8e6..50ea959a381be 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -23,11 +23,13 @@ export { bootstrap } from './bootstrap'; import { first } from 'rxjs/operators'; import { ConfigService, Env } from './config'; +import { ElasticsearchModule } from './elasticsearch'; import { HttpConfig, HttpModule, HttpServerInfo } from './http'; -import { LegacyCompatModule } from './legacy_compat'; +import { LegacyCompatModule } from './legacy'; import { Logger, LoggerFactory } from './logging'; export class Server { + private readonly elasticsearch: ElasticsearchModule; private readonly http: HttpModule; private readonly plugins: PluginsModule; private readonly legacy: LegacyCompatModule; @@ -41,6 +43,7 @@ export class Server { const core = { env, configService, logger }; this.plugins = new PluginsModule(core); this.legacy = new LegacyCompatModule(core); + this.elasticsearch = new ElasticsearchModule(core); } public async start() { @@ -56,9 +59,14 @@ export class Server { httpStart = await this.http.service.start(); } - const pluginsStart = await this.plugins.service.start(); + const elasticsearchServiceStart = await this.elasticsearch.service.start(); + + const pluginsStart = await this.plugins.service.start({ + elasticsearch: elasticsearchServiceStart, + }); await this.legacy.service.start({ + elasticsearch: elasticsearchServiceStart, http: httpStart, plugins: pluginsStart, }); @@ -69,6 +77,7 @@ export class Server { await this.legacy.service.stop(); await this.plugins.service.stop(); + await this.elasticsearch.service.stop(); await this.http.service.stop(); } } diff --git a/src/core/server/legacy_compat/__snapshots__/legacy_service.test.ts.snap b/src/core/server/legacy/__snapshots__/legacy_service.test.ts.snap similarity index 97% rename from src/core/server/legacy_compat/__snapshots__/legacy_service.test.ts.snap rename to src/core/server/legacy/__snapshots__/legacy_service.test.ts.snap index 1734a88912aec..06fd32f2dfa9f 100644 --- a/src/core/server/legacy_compat/__snapshots__/legacy_service.test.ts.snap +++ b/src/core/server/legacy/__snapshots__/legacy_service.test.ts.snap @@ -29,6 +29,9 @@ Array [ }, }, "log": Object { + "context": Array [ + "server", + ], "debug": [MockFunction] { "calls": Array [ Array [ @@ -37,7 +40,7 @@ Array [ ], "results": Array [ Object { - "isThrow": false, + "type": "return", "value": undefined, }, ], diff --git a/src/core/server/legacy_compat/config/__snapshots__/legacy_object_to_config_adapter.test.ts.snap b/src/core/server/legacy/config/__snapshots__/legacy_object_to_config_adapter.test.ts.snap similarity index 100% rename from src/core/server/legacy_compat/config/__snapshots__/legacy_object_to_config_adapter.test.ts.snap rename to src/core/server/legacy/config/__snapshots__/legacy_object_to_config_adapter.test.ts.snap diff --git a/src/core/server/legacy_compat/config/legacy_object_to_config_adapter.test.ts b/src/core/server/legacy/config/legacy_object_to_config_adapter.test.ts similarity index 100% rename from src/core/server/legacy_compat/config/legacy_object_to_config_adapter.test.ts rename to src/core/server/legacy/config/legacy_object_to_config_adapter.test.ts diff --git a/src/core/server/legacy_compat/config/legacy_object_to_config_adapter.ts b/src/core/server/legacy/config/legacy_object_to_config_adapter.ts similarity index 100% rename from src/core/server/legacy_compat/config/legacy_object_to_config_adapter.ts rename to src/core/server/legacy/config/legacy_object_to_config_adapter.ts diff --git a/src/core/server/legacy_compat/index.ts b/src/core/server/legacy/index.ts similarity index 100% rename from src/core/server/legacy_compat/index.ts rename to src/core/server/legacy/index.ts diff --git a/src/core/server/legacy_compat/legacy_platform_proxy.test.ts b/src/core/server/legacy/legacy_platform_proxy.test.ts similarity index 97% rename from src/core/server/legacy_compat/legacy_platform_proxy.test.ts rename to src/core/server/legacy/legacy_platform_proxy.test.ts index cc7436ce32170..29c91bd0b61f9 100644 --- a/src/core/server/legacy_compat/legacy_platform_proxy.test.ts +++ b/src/core/server/legacy/legacy_platform_proxy.test.ts @@ -46,8 +46,8 @@ test('correctly redirects server events.', () => { ([serverEventName]) => serverEventName === eventName )!; - serverListener(1, 2, 3, 4); - serverListener(5, 6, 7, 8); + (serverListener as jest.Mock)(1, 2, 3, 4); + (serverListener as jest.Mock)(5, 6, 7, 8); expect(listener).toHaveBeenCalledTimes(2); expect(listener).toHaveBeenCalledWith(1, 2, 3, 4); diff --git a/src/core/server/legacy_compat/legacy_platform_proxy.ts b/src/core/server/legacy/legacy_platform_proxy.ts similarity index 100% rename from src/core/server/legacy_compat/legacy_platform_proxy.ts rename to src/core/server/legacy/legacy_platform_proxy.ts diff --git a/src/core/server/legacy_compat/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts similarity index 93% rename from src/core/server/legacy_compat/legacy_service.test.ts rename to src/core/server/legacy/legacy_service.test.ts index 8829be572f496..8d083808f9a4c 100644 --- a/src/core/server/legacy_compat/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -30,6 +30,7 @@ import MockClusterManager from '../../../cli/cluster/cluster_manager'; import KbnServer from '../../../legacy/server/kbn_server'; import { Config, ConfigService, Env, ObjectToConfigAdapter } from '../config'; import { getEnvOptions } from '../config/__mocks__/env'; +import { ElasticsearchServiceStart } from '../elasticsearch'; import { logger } from '../logging/__mocks__'; import { PluginsServiceStart } from '../plugins/plugins_service'; import { LegacyPlatformProxy } from './legacy_platform_proxy'; @@ -41,13 +42,18 @@ let legacyService: LegacyService; let configService: jest.Mocked; let env: Env; let config$: BehaviorSubject; -let startDeps: { http: any; plugins: PluginsServiceStart }; +let startDeps: { + elasticsearch: ElasticsearchServiceStart; + http: any; + plugins: PluginsServiceStart; +}; beforeEach(() => { env = Env.createDefault(getEnvOptions()); MockKbnServer.prototype.ready = jest.fn().mockReturnValue(Promise.resolve()); startDeps = { + elasticsearch: { legacy: {} } as any, http: { server: { listener: { addListener: jest.fn() }, route: jest.fn() }, options: { someOption: 'foo', someAnotherOption: 'bar' }, @@ -57,6 +63,7 @@ beforeEach(() => { config$ = new BehaviorSubject( new ObjectToConfigAdapter({ + elasticsearch: { hosts: ['http://127.0.0.1'] }, server: { autoListen: true }, }) ); @@ -148,6 +155,7 @@ describe('once LegacyService is started with connection info', () => { expect(MockKbnServer).toHaveBeenCalledWith( { server: { autoListen: true } }, { + elasticsearch: startDeps.elasticsearch, serverOptions: { listener: expect.any(LegacyPlatformProxy), someAnotherOption: 'bar', @@ -172,6 +180,7 @@ describe('once LegacyService is started with connection info', () => { expect(MockKbnServer).toHaveBeenCalledWith( { server: { autoListen: true } }, { + elasticsearch: startDeps.elasticsearch, serverOptions: { listener: expect.any(LegacyPlatformProxy), someAnotherOption: 'bar', @@ -276,7 +285,13 @@ describe('once LegacyService is started with connection info', () => { }); describe('once LegacyService is started without connection info', () => { - beforeEach(async () => await legacyService.start({ plugins: startDeps.plugins })); + beforeEach( + async () => + await legacyService.start({ + elasticsearch: startDeps.elasticsearch, + plugins: startDeps.plugins, + }) + ); test('creates legacy kbnServer with `autoListen: false`.', () => { expect(startDeps.http.server.route).not.toHaveBeenCalled(); @@ -284,6 +299,7 @@ describe('once LegacyService is started without connection info', () => { expect(MockKbnServer).toHaveBeenCalledWith( { server: { autoListen: true } }, { + elasticsearch: startDeps.elasticsearch, serverOptions: { autoListen: false }, handledConfigPaths: ['foo.bar'], plugins: startDeps.plugins, @@ -324,7 +340,10 @@ describe('once LegacyService is started in `devClusterMaster` mode', () => { configService, }); - await devClusterLegacyService.start({ plugins: new Map() }); + await devClusterLegacyService.start({ + elasticsearch: startDeps.elasticsearch, + plugins: new Map(), + }); expect(MockClusterManager.create.mock.calls).toMatchSnapshot( 'cluster manager without base path proxy' @@ -343,7 +362,10 @@ describe('once LegacyService is started in `devClusterMaster` mode', () => { configService, }); - await devClusterLegacyService.start({ plugins: new Map() }); + await devClusterLegacyService.start({ + elasticsearch: startDeps.elasticsearch, + plugins: new Map(), + }); expect(MockClusterManager.create.mock.calls).toMatchSnapshot( 'cluster manager with base path proxy' diff --git a/src/core/server/legacy_compat/legacy_service.ts b/src/core/server/legacy/legacy_service.ts similarity index 89% rename from src/core/server/legacy_compat/legacy_service.ts rename to src/core/server/legacy/legacy_service.ts index a6fdd1f65e3bf..6bd4ff79d2439 100644 --- a/src/core/server/legacy_compat/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -23,6 +23,7 @@ import { first, map, mergeMap, publishReplay, tap } from 'rxjs/operators'; import { CoreContext, CoreService } from '../../types'; import { Config } from '../config'; import { DevConfig } from '../dev'; +import { ElasticsearchServiceStart } from '../elasticsearch'; import { BasePathProxyServer, HttpConfig, HttpServiceStart } from '../http'; import { Logger } from '../logging'; import { PluginsServiceStart } from '../plugins/plugins_service'; @@ -36,10 +37,23 @@ interface LegacyKbnServer { } interface Deps { + elasticsearch: ElasticsearchServiceStart; http?: HttpServiceStart; plugins: PluginsServiceStart; } +function getLegacyRawConfig(config: Config) { + const rawConfig = config.toRaw(); + + // Elasticsearch config is solely handled by the core and legacy platform + // shouldn't have direct access to it. + if (rawConfig.elasticsearch !== undefined) { + delete rawConfig.elasticsearch; + } + + return rawConfig; +} + /** @internal */ export class LegacyService implements CoreService { private readonly log: Logger; @@ -111,28 +125,29 @@ export class LegacyService implements CoreService { require('../../../cli/cluster/cluster_manager').create( this.coreContext.env.cliArgs, - config.toRaw(), + getLegacyRawConfig(config), await basePathProxy$.toPromise() ); } - private async createKbnServer(config: Config, deps: Deps) { + private async createKbnServer(config: Config, { elasticsearch, http, plugins }: Deps) { const KbnServer = require('../../../legacy/server/kbn_server'); - const kbnServer: LegacyKbnServer = new KbnServer(config.toRaw(), { + const kbnServer: LegacyKbnServer = new KbnServer(getLegacyRawConfig(config), { // If core HTTP service is run we'll receive internal server reference and // options that were used to create that server so that we can properly // bridge with the "legacy" Kibana. If server isn't run (e.g. if process is // managed by ClusterManager or optimizer) then we won't have that info, // so we can't start "legacy" server either. serverOptions: - deps.http !== undefined + http !== undefined ? { - ...deps.http.options, - listener: this.setupProxyListener(deps.http.server), + ...http.options, + listener: this.setupProxyListener(http.server), } : { autoListen: false }, handledConfigPaths: await this.coreContext.configService.getUsedPaths(), - plugins: deps.plugins, + elasticsearch, + plugins, }); // The kbnWorkerType check is necessary to prevent the repl diff --git a/src/core/server/legacy_compat/logging/appenders/__snapshots__/legacy_appender.test.ts.snap b/src/core/server/legacy/logging/appenders/__snapshots__/legacy_appender.test.ts.snap similarity index 100% rename from src/core/server/legacy_compat/logging/appenders/__snapshots__/legacy_appender.test.ts.snap rename to src/core/server/legacy/logging/appenders/__snapshots__/legacy_appender.test.ts.snap diff --git a/src/core/server/legacy_compat/logging/appenders/legacy_appender.test.ts b/src/core/server/legacy/logging/appenders/legacy_appender.test.ts similarity index 100% rename from src/core/server/legacy_compat/logging/appenders/legacy_appender.test.ts rename to src/core/server/legacy/logging/appenders/legacy_appender.test.ts diff --git a/src/core/server/legacy_compat/logging/appenders/legacy_appender.ts b/src/core/server/legacy/logging/appenders/legacy_appender.ts similarity index 100% rename from src/core/server/legacy_compat/logging/appenders/legacy_appender.ts rename to src/core/server/legacy/logging/appenders/legacy_appender.ts diff --git a/src/core/server/legacy_compat/logging/legacy_logging_server.test.ts b/src/core/server/legacy/logging/legacy_logging_server.test.ts similarity index 100% rename from src/core/server/legacy_compat/logging/legacy_logging_server.test.ts rename to src/core/server/legacy/logging/legacy_logging_server.test.ts diff --git a/src/core/server/legacy_compat/logging/legacy_logging_server.ts b/src/core/server/legacy/logging/legacy_logging_server.ts similarity index 100% rename from src/core/server/legacy_compat/logging/legacy_logging_server.ts rename to src/core/server/legacy/logging/legacy_logging_server.ts diff --git a/src/core/server/logging/__mocks__/index.ts b/src/core/server/logging/__mocks__/index.ts index 400521f6077fb..76e78c526fc32 100644 --- a/src/core/server/logging/__mocks__/index.ts +++ b/src/core/server/logging/__mocks__/index.ts @@ -51,7 +51,10 @@ const mockCollect = () => ({ }); export const logger = { - get: jest.fn(() => mockLog), + get: jest.fn((...context) => ({ + context, + ...mockLog, + })), mockClear, mockCollect, mockLog, diff --git a/src/core/server/logging/appenders/appenders.test.ts b/src/core/server/logging/appenders/appenders.test.ts index dea4b117b7d40..df528f4c58cd5 100644 --- a/src/core/server/logging/appenders/appenders.test.ts +++ b/src/core/server/logging/appenders/appenders.test.ts @@ -28,7 +28,7 @@ jest.mock('../layouts/layouts', () => { }; }); -import { LegacyAppender } from '../../legacy_compat/logging/appenders/legacy_appender'; +import { LegacyAppender } from '../../legacy/logging/appenders/legacy_appender'; import { Appenders } from './appenders'; import { ConsoleAppender } from './console/console_appender'; import { FileAppender } from './file/file_appender'; diff --git a/src/core/server/logging/appenders/appenders.ts b/src/core/server/logging/appenders/appenders.ts index 5639899fde2b1..3aa86495e4d82 100644 --- a/src/core/server/logging/appenders/appenders.ts +++ b/src/core/server/logging/appenders/appenders.ts @@ -20,7 +20,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { assertNever } from '../../../utils'; -import { LegacyAppender } from '../../legacy_compat/logging/appenders/legacy_appender'; +import { LegacyAppender } from '../../legacy/logging/appenders/legacy_appender'; import { Layouts } from '../layouts/layouts'; import { LogRecord } from '../log_record'; import { ConsoleAppender } from './console/console_appender'; diff --git a/src/core/server/logging/logger.test.ts b/src/core/server/logging/logger.test.ts index 61eaa4912185b..928b37a3f510e 100644 --- a/src/core/server/logging/logger.test.ts +++ b/src/core/server/logging/logger.test.ts @@ -25,15 +25,18 @@ import { BaseLogger } from './logger'; const context = LoggingConfig.getLoggerContext(['context', 'parent', 'child']); let appenderMocks: Appender[]; let logger: BaseLogger; - const timestamp = new Date(2012, 1, 1); -jest.spyOn(global, 'Date').mockImplementation(() => timestamp); - beforeEach(() => { + jest.spyOn(global, 'Date').mockImplementation(() => timestamp); + appenderMocks = [{ append: jest.fn() }, { append: jest.fn() }]; logger = new BaseLogger(context, LogLevel.All, appenderMocks); }); +afterEach(() => { + jest.restoreAllMocks(); +}); + test('`trace()` correctly forms `LogRecord` and passes it to all appenders.', () => { logger.trace('message-1'); for (const appenderMock of appenderMocks) { diff --git a/src/core/server/logging/logging_service.test.ts b/src/core/server/logging/logging_service.test.ts index b6aeb88b50052..ee56b777b63b2 100644 --- a/src/core/server/logging/logging_service.test.ts +++ b/src/core/server/logging/logging_service.test.ts @@ -24,21 +24,22 @@ jest.mock('fs', () => ({ })); const timestamp = new Date(Date.UTC(2012, 1, 1)); -const mockConsoleLog = jest.spyOn(global.console, 'log').mockImplementation(() => { - // noop -}); -jest.spyOn(global, 'Date').mockImplementation(() => timestamp); +let mockConsoleLog: jest.SpyInstance; import { createWriteStream } from 'fs'; -const mockCreateWriteStream = createWriteStream as jest.Mock; +const mockCreateWriteStream = (createWriteStream as unknown) as jest.Mock; import { LoggingConfig, LoggingService } from '.'; let service: LoggingService; -beforeEach(() => (service = new LoggingService())); +beforeEach(() => { + mockConsoleLog = jest.spyOn(global.console, 'log').mockReturnValue(undefined); + jest.spyOn(global, 'Date').mockImplementation(() => timestamp); + service = new LoggingService(); +}); afterEach(() => { - mockConsoleLog.mockClear(); + jest.restoreAllMocks(); mockCreateWriteStream.mockClear(); mockStreamWrite.mockClear(); }); diff --git a/src/core/server/plugins/plugin.test.ts b/src/core/server/plugins/plugin.test.ts index ca26c4e9ed5e2..83e4db82d4245 100644 --- a/src/core/server/plugins/plugin.test.ts +++ b/src/core/server/plugins/plugin.test.ts @@ -22,6 +22,7 @@ import { BehaviorSubject } from 'rxjs'; import { CoreContext } from '../../types'; import { Config, ConfigService, Env, ObjectToConfigAdapter } from '../config'; import { getEnvOptions } from '../config/__mocks__/env'; +import { ElasticsearchServiceStart } from '../elasticsearch'; import { logger } from '../logging/__mocks__'; import { Plugin, PluginManifest } from './plugin'; import { createPluginInitializerContext, createPluginStartContext } from './plugin_context'; @@ -56,8 +57,10 @@ function createPluginManifest(manifestProps: Partial = {}): Plug let configService: ConfigService; let env: Env; let coreContext: CoreContext; +let startDeps: { elasticsearch: ElasticsearchServiceStart }; beforeEach(() => { env = Env.createDefault(getEnvOptions()); + startDeps = { elasticsearch: { adminClient$: {}, dataClient$: {} } as any }; configService = new ConfigService( new BehaviorSubject(new ObjectToConfigAdapter({ plugins: { initialize: true } })), @@ -96,7 +99,7 @@ test('`start` fails if `plugin` initializer is not exported', async () => { ); await expect( - plugin.start(createPluginStartContext(coreContext, plugin), {}) + plugin.start(createPluginStartContext(coreContext, startDeps, plugin), {}) ).rejects.toMatchInlineSnapshot( `[Error: Plugin "some-plugin-id" does not export "plugin" definition (plugin-without-initializer-path).]` ); @@ -111,7 +114,7 @@ test('`start` fails if plugin initializer is not a function', async () => { ); await expect( - plugin.start(createPluginStartContext(coreContext, plugin), {}) + plugin.start(createPluginStartContext(coreContext, startDeps, plugin), {}) ).rejects.toMatchInlineSnapshot( `[Error: Definition of plugin "some-plugin-id" should be a function (plugin-with-wrong-initializer-path).]` ); @@ -128,7 +131,7 @@ test('`start` fails if initializer does not return object', async () => { mockPluginInitializer.mockReturnValue(null); await expect( - plugin.start(createPluginStartContext(coreContext, plugin), {}) + plugin.start(createPluginStartContext(coreContext, startDeps, plugin), {}) ).rejects.toMatchInlineSnapshot( `[Error: Initializer for plugin "some-plugin-id" is expected to return plugin instance, but returned "null".]` ); @@ -146,7 +149,7 @@ test('`start` fails if object returned from initializer does not define `start` mockPluginInitializer.mockReturnValue(mockPluginInstance); await expect( - plugin.start(createPluginStartContext(coreContext, plugin), {}) + plugin.start(createPluginStartContext(coreContext, startDeps, plugin), {}) ).rejects.toMatchInlineSnapshot( `[Error: Instance of plugin "some-plugin-id" does not define "start" function.]` ); @@ -160,7 +163,7 @@ test('`start` initializes plugin and calls appropriate lifecycle hook', async () const mockPluginInstance = { start: jest.fn().mockResolvedValue({ contract: 'yes' }) }; mockPluginInitializer.mockReturnValue(mockPluginInstance); - const startContext = createPluginStartContext(coreContext, plugin); + const startContext = createPluginStartContext(coreContext, startDeps, plugin); const startDependencies = { 'some-required-dep': { contract: 'no' } }; await expect(plugin.start(startContext, startDependencies)).resolves.toEqual({ contract: 'yes' }); @@ -197,7 +200,7 @@ test('`stop` does nothing if plugin does not define `stop` function', async () = ); mockPluginInitializer.mockReturnValue({ start: jest.fn() }); - await plugin.start(createPluginStartContext(coreContext, plugin), {}); + await plugin.start(createPluginStartContext(coreContext, startDeps, plugin), {}); await expect(plugin.stop()).resolves.toBeUndefined(); }); @@ -212,7 +215,7 @@ test('`stop` calls `stop` defined by the plugin instance', async () => { const mockPluginInstance = { start: jest.fn(), stop: jest.fn() }; mockPluginInitializer.mockReturnValue(mockPluginInstance); - await plugin.start(createPluginStartContext(coreContext, plugin), {}); + await plugin.start(createPluginStartContext(coreContext, startDeps, plugin), {}); await expect(plugin.stop()).resolves.toBeUndefined(); expect(mockPluginInstance.stop).toHaveBeenCalledTimes(1); diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index 2382209baea02..1bf2a71f0dcf4 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -21,9 +21,14 @@ import { Type } from '@kbn/config-schema'; import { Observable } from 'rxjs'; import { CoreContext } from '../../types'; import { ConfigWithSchema, EnvironmentMode } from '../config'; +import { ClusterClient } from '../elasticsearch'; import { LoggerFactory } from '../logging'; import { Plugin, PluginManifest } from './plugin'; +import { PluginsServiceStartDeps } from './plugins_service'; +/** + * Context that's available to plugins during initialization stage. + */ export interface PluginInitializerContext { env: { mode: EnvironmentMode }; logger: LoggerFactory; @@ -37,8 +42,15 @@ export interface PluginInitializerContext { }; } -// tslint:disable no-empty-interface -export interface PluginStartContext {} +/** + * Context passed to the plugins `start` method. + */ +export interface PluginStartContext { + elasticsearch: { + adminClient$: Observable; + dataClient$: Observable; + }; +} /** * This returns a facade for `CoreContext` that will be exposed to the plugin initializer. @@ -104,11 +116,18 @@ export function createPluginInitializerContext( * * @param coreContext Kibana core context * @param plugin The plugin we're building these values for. + * @param deps Dependencies that Plugins services gets during start. * @internal */ export function createPluginStartContext( coreContext: CoreContext, + deps: PluginsServiceStartDeps, plugin: Plugin ): PluginStartContext { - return {}; + return { + elasticsearch: { + adminClient$: deps.elasticsearch.adminClient$, + dataClient$: deps.elasticsearch.dataClient$, + }, + }; } diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index cefb023db338b..3b4d459a3175d 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -17,6 +17,8 @@ * under the License. */ +import { ElasticsearchServiceStart } from '../elasticsearch'; + const mockPackage = new Proxy({ raw: {} as any }, { get: (obj, prop) => obj.raw[prop] }); jest.mock('../../../legacy/utils/package_json', () => ({ pkg: mockPackage })); @@ -42,6 +44,7 @@ let pluginsService: PluginsService; let configService: ConfigService; let env: Env; let mockPluginSystem: jest.Mocked; +let startDeps: { elasticsearch: ElasticsearchServiceStart }; beforeEach(() => { mockPackage.raw = { branch: 'feature-v1', @@ -54,6 +57,7 @@ beforeEach(() => { }; env = Env.createDefault(getEnvOptions()); + startDeps = { elasticsearch: { legacy: {} } as any }; configService = new ConfigService( new BehaviorSubject(new ObjectToConfigAdapter({ plugins: { initialize: true } })), @@ -75,7 +79,7 @@ test('`start` throws if plugin has an invalid manifest', async () => { plugin$: from([]), }); - await expect(pluginsService.start()).rejects.toMatchInlineSnapshot(` + await expect(pluginsService.start(startDeps)).rejects.toMatchInlineSnapshot(` [Error: Failed to initialize plugins: Invalid JSON (invalid-manifest, path-1)] `); @@ -96,7 +100,7 @@ test('`start` throws if plugin required Kibana version is incompatible with the plugin$: from([]), }); - await expect(pluginsService.start()).rejects.toMatchInlineSnapshot(` + await expect(pluginsService.start(startDeps)).rejects.toMatchInlineSnapshot(` [Error: Failed to initialize plugins: Incompatible version (incompatible-version, path-3)] `); @@ -144,7 +148,7 @@ test('`start` throws if discovered plugins with conflicting names', async () => ]), }); - await expect(pluginsService.start()).rejects.toMatchInlineSnapshot( + await expect(pluginsService.start(startDeps)).rejects.toMatchInlineSnapshot( `[Error: Plugin with id "conflicting-id" is already registered!]` ); @@ -221,9 +225,10 @@ test('`start` properly detects plugins that should be disabled.', async () => { ]), }); - expect(await pluginsService.start()).toBeInstanceOf(Map); + expect(await pluginsService.start(startDeps)).toBeInstanceOf(Map); expect(mockPluginSystem.addPlugin).not.toHaveBeenCalled(); expect(mockPluginSystem.startPlugins).toHaveBeenCalledTimes(1); + expect(mockPluginSystem.startPlugins).toHaveBeenCalledWith(startDeps); expect(logger.mockCollect().info).toMatchInlineSnapshot(` Array [ @@ -286,7 +291,7 @@ test('`start` properly invokes `discover` and ignores non-critical errors.', asy const pluginsStart = new Map(); mockPluginSystem.startPlugins.mockResolvedValue(pluginsStart); - const start = await pluginsService.start(); + const start = await pluginsService.start(startDeps); expect(start).toBe(pluginsStart); expect(mockPluginSystem.addPlugin).toHaveBeenCalledTimes(2); diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index cab77f85e3fd0..e63f733caa900 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -20,6 +20,7 @@ import { Observable } from 'rxjs'; import { filter, first, mergeMap, tap, toArray } from 'rxjs/operators'; import { CoreContext, CoreService } from '../../types'; +import { ElasticsearchServiceStart } from '../elasticsearch'; import { Logger } from '../logging'; import { discover, PluginDiscoveryError, PluginDiscoveryErrorType } from './discovery'; import { Plugin, PluginName } from './plugin'; @@ -29,6 +30,11 @@ import { PluginsSystem } from './plugins_system'; /** @internal */ export type PluginsServiceStart = Map; +/** @internal */ +export interface PluginsServiceStartDeps { + elasticsearch: ElasticsearchServiceStart; +} + /** @internal */ export class PluginsService implements CoreService { private readonly log: Logger; @@ -39,7 +45,7 @@ export class PluginsService implements CoreService { this.pluginsSystem = new PluginsSystem(coreContext); } - public async start() { + public async start(deps: PluginsServiceStartDeps) { this.log.debug('Starting plugins service'); const config = await this.coreContext.configService @@ -56,7 +62,7 @@ export class PluginsService implements CoreService { return new Map(); } - return await this.pluginsSystem.startPlugins(); + return await this.pluginsSystem.startPlugins(deps); } public async stop() { diff --git a/src/core/server/plugins/plugins_system.test.ts b/src/core/server/plugins/plugins_system.test.ts index 8c2b44b59f914..e594d4eda3a53 100644 --- a/src/core/server/plugins/plugins_system.test.ts +++ b/src/core/server/plugins/plugins_system.test.ts @@ -27,6 +27,7 @@ jest.mock('./plugin_context', () => ({ import { BehaviorSubject } from 'rxjs'; import { Config, ConfigService, Env, ObjectToConfigAdapter } from '../config'; import { getEnvOptions } from '../config/__mocks__/env'; +import { ElasticsearchServiceStart } from '../elasticsearch'; import { logger } from '../logging/__mocks__'; import { Plugin, PluginName } from './plugin'; import { PluginsSystem } from './plugins_system'; @@ -59,8 +60,10 @@ let pluginsSystem: PluginsSystem; let configService: ConfigService; let env: Env; let coreContext: CoreContext; +let startDeps: { elasticsearch: ElasticsearchServiceStart }; beforeEach(() => { env = Env.createDefault(getEnvOptions()); + startDeps = { elasticsearch: { legacy: {} } as any }; configService = new ConfigService( new BehaviorSubject(new ObjectToConfigAdapter({ plugins: { initialize: true } })), @@ -78,7 +81,7 @@ afterEach(() => { }); test('can be started even without plugins', async () => { - const pluginsStart = await pluginsSystem.startPlugins(); + const pluginsStart = await pluginsSystem.startPlugins(startDeps); expect(pluginsStart).toBeInstanceOf(Map); expect(pluginsStart.size).toBe(0); @@ -87,7 +90,7 @@ test('can be started even without plugins', async () => { test('`startPlugins` throws plugin has missing required dependency', async () => { pluginsSystem.addPlugin(createPlugin('some-id', { required: ['missing-dep'] })); - await expect(pluginsSystem.startPlugins()).rejects.toMatchInlineSnapshot( + await expect(pluginsSystem.startPlugins(startDeps)).rejects.toMatchInlineSnapshot( `[Error: Topological ordering of plugins did not complete, these edges could not be ordered: [["some-id",{}]]]` ); }); @@ -97,7 +100,7 @@ test('`startPlugins` throws if plugins have circular required dependency', async pluginsSystem.addPlugin(createPlugin('depends-on-1', { required: ['depends-on-2'] })); pluginsSystem.addPlugin(createPlugin('depends-on-2', { required: ['depends-on-1'] })); - await expect(pluginsSystem.startPlugins()).rejects.toMatchInlineSnapshot( + await expect(pluginsSystem.startPlugins(startDeps)).rejects.toMatchInlineSnapshot( `[Error: Topological ordering of plugins did not complete, these edges could not be ordered: [["depends-on-1",{}],["depends-on-2",{}]]]` ); }); @@ -107,7 +110,7 @@ test('`startPlugins` throws if plugins have circular optional dependency', async pluginsSystem.addPlugin(createPlugin('depends-on-1', { optional: ['depends-on-2'] })); pluginsSystem.addPlugin(createPlugin('depends-on-2', { optional: ['depends-on-1'] })); - await expect(pluginsSystem.startPlugins()).rejects.toMatchInlineSnapshot( + await expect(pluginsSystem.startPlugins(startDeps)).rejects.toMatchInlineSnapshot( `[Error: Topological ordering of plugins did not complete, these edges could not be ordered: [["depends-on-1",{}],["depends-on-2",{}]]]` ); }); @@ -118,7 +121,7 @@ test('`startPlugins` ignores missing optional dependency', async () => { pluginsSystem.addPlugin(plugin); - expect([...(await pluginsSystem.startPlugins())]).toMatchInlineSnapshot(` + expect([...(await pluginsSystem.startPlugins(startDeps))]).toMatchInlineSnapshot(` Array [ Array [ "some-id", @@ -153,9 +156,11 @@ test('`startPlugins` correctly orders plugins and returns exposed values', async pluginsSystem.addPlugin(plugin); }); - mockCreatePluginStartContext.mockImplementation((_, plugin) => startContextMap.get(plugin.name)); + mockCreatePluginStartContext.mockImplementation((context, deps, plugin) => + startContextMap.get(plugin.name) + ); - expect([...(await pluginsSystem.startPlugins())]).toMatchInlineSnapshot(` + expect([...(await pluginsSystem.startPlugins(startDeps))]).toMatchInlineSnapshot(` Array [ Array [ "order-0", @@ -181,7 +186,7 @@ Array [ `); for (const [plugin, deps] of plugins) { - expect(mockCreatePluginStartContext).toHaveBeenCalledWith(coreContext, plugin); + expect(mockCreatePluginStartContext).toHaveBeenCalledWith(coreContext, startDeps, plugin); expect(plugin.start).toHaveBeenCalledTimes(1); expect(plugin.start).toHaveBeenCalledWith(startContextMap.get(plugin.name), deps); } @@ -198,7 +203,7 @@ test('`startPlugins` only starts plugins that have server side', async () => { pluginsSystem.addPlugin(plugin); }); - expect([...(await pluginsSystem.startPlugins())]).toMatchInlineSnapshot(` + expect([...(await pluginsSystem.startPlugins(startDeps))]).toMatchInlineSnapshot(` Array [ Array [ "order-1", @@ -211,9 +216,17 @@ Array [ ] `); - expect(mockCreatePluginStartContext).toHaveBeenCalledWith(coreContext, firstPluginToRun); + expect(mockCreatePluginStartContext).toHaveBeenCalledWith( + coreContext, + startDeps, + firstPluginToRun + ); expect(mockCreatePluginStartContext).not.toHaveBeenCalledWith(coreContext, secondPluginNotToRun); - expect(mockCreatePluginStartContext).toHaveBeenCalledWith(coreContext, thirdPluginToRun); + expect(mockCreatePluginStartContext).toHaveBeenCalledWith( + coreContext, + startDeps, + thirdPluginToRun + ); expect(firstPluginToRun.start).toHaveBeenCalledTimes(1); expect(secondPluginNotToRun.start).not.toHaveBeenCalled(); diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index 942dcb2d5707c..49dcfc6055cd9 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -21,6 +21,7 @@ import { CoreContext } from '../../types'; import { Logger } from '../logging'; import { Plugin, PluginName } from './plugin'; import { createPluginStartContext } from './plugin_context'; +import { PluginsServiceStartDeps } from './plugins_service'; /** @internal */ export class PluginsSystem { @@ -36,7 +37,7 @@ export class PluginsSystem { this.plugins.set(plugin.name, plugin); } - public async startPlugins() { + public async startPlugins(deps: PluginsServiceStartDeps) { const exposedValues = new Map(); if (this.plugins.size === 0) { return exposedValues; @@ -67,7 +68,7 @@ export class PluginsSystem { exposedValues.set( pluginName, await plugin.start( - createPluginStartContext(this.coreContext, plugin), + createPluginStartContext(this.coreContext, deps, plugin), exposedDependencyValues ) ); diff --git a/src/core/server/root/index.test.ts b/src/core/server/root/index.test.ts index 0fbb917fdeef4..a65506f2ba1d2 100644 --- a/src/core/server/root/index.test.ts +++ b/src/core/server/root/index.test.ts @@ -40,23 +40,18 @@ import { logger } from '../logging/__mocks__'; const env = new Env('.', getEnvOptions()); const config$ = new BehaviorSubject({} as Config); -const mockProcessExit = jest.spyOn(global.process, 'exit').mockImplementation(() => { - // noop -}); - -const mockConsoleError = jest.spyOn(console, 'error').mockImplementation(() => { - // noop -}); +let mockConsoleError: jest.SpyInstance; beforeEach(() => { + jest.spyOn(global.process, 'exit').mockReturnValue(undefined as never); + mockConsoleError = jest.spyOn(console, 'error').mockReturnValue(undefined); mockLoggingService.asLoggerFactory.mockReturnValue(logger); mockConfigService.getConfig$.mockReturnValue(new BehaviorSubject({})); mockConfigService.atPath.mockReturnValue(new BehaviorSubject({ someValue: 'foo' })); }); afterEach(() => { - mockProcessExit.mockReset(); - mockConsoleError.mockReset(); + jest.restoreAllMocks(); mockLoggingService.upgrade.mockReset(); mockLoggingService.stop.mockReset(); @@ -178,7 +173,7 @@ test('fails and stops services if initial logger upgrade fails', async () => { test('stops services if consequent logger upgrade fails', async () => { const onShutdown = new BehaviorSubject(null); - const mockOnShutdown = jest.fn(() => { + const mockOnShutdown = jest.fn(() => { onShutdown.next('completed'); onShutdown.complete(); }); diff --git a/src/core/utils/pick.ts b/src/core/utils/pick.ts index 513517394362a..d55c76a3ca77d 100644 --- a/src/core/utils/pick.ts +++ b/src/core/utils/pick.ts @@ -17,17 +17,18 @@ * under the License. */ -export function pick( +export function pick, K extends keyof T>( obj: T, keys: K[] ): Pick { - const newObj = keys.reduce( - (acc, val) => { - acc[val] = obj[val]; + return keys.reduce( + (acc, key) => { + if (obj.hasOwnProperty(key)) { + acc[key] = obj[key]; + } + return acc; }, - {} as { [k: string]: any } + {} as Pick ); - - return newObj as Pick; } diff --git a/src/dev/build/build_distributables.js b/src/dev/build/build_distributables.js index 7425565d585d9..cda00064162f2 100644 --- a/src/dev/build/build_distributables.js +++ b/src/dev/build/build_distributables.js @@ -52,6 +52,7 @@ import { UpdateLicenseFileTask, VerifyEnvTask, VerifyExistingNodeBuildsTask, + PathLengthTask, WriteShaSumsTask, } from './tasks'; @@ -134,6 +135,8 @@ export async function buildDistributables(options) { await run(CleanExtraBrowsersTask); await run(CleanNodeBuildsTask); + await run(PathLengthTask); + /** * package platform-specific builds into archives * or os-specific packages in the target directory diff --git a/src/dev/build/lib/fs.js b/src/dev/build/lib/fs.js index cc0f5975a2de9..e554d8c8a0b27 100644 --- a/src/dev/build/lib/fs.js +++ b/src/dev/build/lib/fs.js @@ -34,11 +34,11 @@ import { Extract } from 'tar'; const mkdirpAsync = promisify(mkdirpCb); const statAsync = promisify(fs.stat); -const chmodAsync = promisify(fs.chmod); const writeFileAsync = promisify(fs.writeFile); const readFileAsync = promisify(fs.readFile); const readdirAsync = promisify(fs.readdir); const utimesAsync = promisify(fs.utimes); +const copyFileAsync = promisify(fs.copyFile); export function assertAbsolute(path) { if (!isAbsolute(path)) { @@ -80,19 +80,10 @@ export async function copy(source, destination) { assertAbsolute(source); assertAbsolute(destination); - const stat = await statAsync(source); - - // mkdirp after the stat(), stat will throw if source - // doesn't exist and ideally we won't create the parent directory - // unless the source exists + // do a stat call to make sure the source exists before creating the destination directory + await statAsync(source); await mkdirp(dirname(destination)); - - await createPromiseFromStreams([ - fs.createReadStream(source), - fs.createWriteStream(destination), - ]); - - await chmodAsync(destination, stat.mode); + await copyFileAsync(source, destination, fs.constants.COPYFILE_FICLONE); } export async function deleteAll(patterns, log) { diff --git a/src/dev/build/lib/scan.ts b/src/dev/build/lib/scan.ts new file mode 100644 index 0000000000000..45e61ca051879 --- /dev/null +++ b/src/dev/build/lib/scan.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 Fs from 'fs'; + +import { join } from 'path'; +import * as Rx from 'rxjs'; +import { map, mergeAll, mergeMap } from 'rxjs/operators'; + +// @ts-ignore +import { assertAbsolute } from './fs'; + +const getStat$ = Rx.bindNodeCallback(Fs.stat) as (path: string) => Rx.Observable; +const getReadDir$ = Rx.bindNodeCallback(Fs.readdir) as (path: string) => Rx.Observable; + +/** + * Return an observable of all files in a directory, starting with the + * directory argument and including all of its children recursivly, + * including dot files. + * + * @param directory the directory to scan + */ +export function scan$(directory: string) { + // get an observable of absolute paths within a directory + const getChildPath$ = (path: string) => + getReadDir$(path).pipe( + mergeAll(), + map((name: string) => join(path, name)) + ); + + // get an observable for the argument paths and all of its child + // paths if it is a path to a directory, recursively + const getPaths$ = (path: string): Rx.Observable => { + return Rx.concat( + [path], + getStat$(path).pipe( + mergeMap(stat => (stat.isDirectory() ? getChildPath$(path) : Rx.EMPTY)), + mergeMap(getPaths$) + ) + ); + }; + + return getPaths$(directory); +} diff --git a/src/dev/build/tasks/index.js b/src/dev/build/tasks/index.js index 7827dd569a4c4..ecf86d6af23eb 100644 --- a/src/dev/build/tasks/index.js +++ b/src/dev/build/tasks/index.js @@ -37,3 +37,4 @@ export * from './transpile_typescript_task'; export * from './transpile_scss_task'; export * from './verify_env_task'; export * from './write_sha_sums_task'; +export * from './path_length_task'; diff --git a/src/dev/build/tasks/path_length_task.js b/src/dev/build/tasks/path_length_task.js new file mode 100644 index 0000000000000..9ad575bdce272 --- /dev/null +++ b/src/dev/build/tasks/path_length_task.js @@ -0,0 +1,48 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { relative } from 'path'; + +import { tap, filter, map, toArray } from 'rxjs/operators'; + +import { scan$ } from '../lib/scan'; + +export const PathLengthTask = { + description: 'Checking Windows for paths > 200 characters', + + async run(config, log, build) { + const buildRoot = build.resolvePath(); + await scan$(buildRoot).pipe( + map(path => relative(buildRoot, path)), + filter(relativePath => relativePath.length > 200), + toArray(), + tap(tooLongPaths => { + if (!tooLongPaths.length) { + return; + } + + throw new Error( + 'Windows has a path limit of 260 characters so we limit the length of paths in Kibana to 200 characters ' + + ' and the following files exceed this limit:' + + '\n - ' + tooLongPaths.join('\n - ') + ); + }) + ).toPromise(); + } +}; diff --git a/src/dev/build/tasks/transpile_scss_task.js b/src/dev/build/tasks/transpile_scss_task.js index ccc7e29ecf1d0..61e86f3db0759 100644 --- a/src/dev/build/tasks/transpile_scss_task.js +++ b/src/dev/build/tasks/transpile_scss_task.js @@ -34,7 +34,13 @@ export const TranspileScssTask = { const uiExports = collectUiExports(enabledPlugins); try { - const bundles = await buildAll(uiExports.styleSheetPaths, log, build.resolvePath('built_assets/css')); + const bundles = await buildAll({ + styleSheets: uiExports.styleSheetPaths, + log, + buildDir: build.resolvePath('built_assets/css'), + outputStyle: 'compressed', + sourceMap: false + }); bundles.forEach(bundle => log.info(`Compiled SCSS: ${bundle.sourcePath} (theme=${bundle.theme})`)); } catch (error) { const { message, line, file } = error; diff --git a/src/dev/i18n/README.md b/src/dev/i18n/README.md index 765b887f82bf0..69bcf1d496f97 100644 --- a/src/dev/i18n/README.md +++ b/src/dev/i18n/README.md @@ -4,7 +4,7 @@ ### Description -The tool is used to extract default messages from all `*.{js, ts, jsx, tsx, html, handlebars, hbs, pug}` files in provided plugins directories to a JSON file. +The tool is used to extract default messages from all `*.{js, ts, jsx, tsx, html, pug}` files in provided plugins directories to a JSON file. It uses Babel to parse code and build an AST for each file or a single JS expression if whole file parsing is impossible. The tool is able to validate, extract and match IDs, default messages and descriptions only if they are defined statically and together, otherwise it will fail with detailed explanation. That means one can't define ID in one place and default message in another, or use function call to dynamically create default message etc. @@ -128,15 +128,6 @@ The `description` is optional, `values` is optional too unless `defaultMessage` * Expression in `#{...}` is parsed as a JS expression. -* **Handlebars (.handlebars, .hbs)** - - ```hbs - {{i18n 'pluginNamespace.messageId' '{"defaultMessage": "Default message string literal", "description": "Message context or description"}'}} - ``` - - * The `values` and `description` are optional. - * The third token (the second argument of i18n function call) should be a string literal that contains a valid JSON. - ### Usage ```bash @@ -203,3 +194,36 @@ integrating translations to has changed and some translations are not needed any ### Output Unless `--target` is specified, the tool generates locale files in plugin folders and few other special locations based on namespaces and corresponding mappings defined in [.i18nrc.json](../../../.i18nrc.json). + + +## Validation tool + +### Description + +The tool performs a number of checks on internationalized labels and verifies whether they don't conflict with the existing translations. + +### Notes + +We don't catch every possible misuse of i18n framework, but only the most common and critical ones. + +To perform translations compatibility checks tool relies on existing translations referenced in `translations` section of [.i18nrc.json](../../../.i18nrc.json). + +Currently auto-fixer (`--fix`) can only automatically fix two types of errors, and for both of them the fix is just removing of conflicting translation entries from JSON files: + +* incompatible translation - this error means that the value references in internationalized label differ from the ones +in the existing translation + +* unused translation - this error means that the translations file includes label that doesn't exist anymore. + +### Usage + +```bash +node scripts/i18n_check --fix +``` + +* `--fix` tells the tool to try to fix as much violations as possible. All errors that tool won't be able to fix will be reported. +* `--ignore-incompatible` specifies whether tool should ignore incompatible translations. +* `--ignore-missing` specifies whether tool should ignore missing translations. +* `--ignore-unused` specifies whether tool should ignore unused translations. +* `--include-config` specifies additional paths to `.i18nrc.json` files (may be useful for 3rd-party plugins) + diff --git a/src/dev/i18n/__fixtures__/extract_default_translations/test_plugin_1/test_file_3.hbs b/src/dev/i18n/__fixtures__/extract_default_translations/test_plugin_1/test_file_3.hbs deleted file mode 100644 index 3908d7e77847a..0000000000000 --- a/src/dev/i18n/__fixtures__/extract_default_translations/test_plugin_1/test_file_3.hbs +++ /dev/null @@ -1,10 +0,0 @@ -(function next() { - var failure = function () { - failure = function () {}; - - var err = document.createElement('h1'); - err.innerText = '{{i18n 'plugin_1.id_6' '{"defaultMessage": "Message 6"}'}}'; - - document.body.innerHTML = err.outerHTML; - } -}()); diff --git a/src/dev/i18n/__snapshots__/extract_default_translations.test.js.snap b/src/dev/i18n/__snapshots__/extract_default_translations.test.js.snap index 0f33e02ca82d5..2c86934d7c71d 100644 --- a/src/dev/i18n/__snapshots__/extract_default_translations.test.js.snap +++ b/src/dev/i18n/__snapshots__/extract_default_translations.test.js.snap @@ -37,13 +37,6 @@ Array [ "message": "Message 5", }, ], - Array [ - "plugin_1.id_6", - Object { - "description": "", - "message": "Message 6", - }, - ], Array [ "plugin_1.id_7", Object { diff --git a/src/dev/i18n/extract_default_translations.js b/src/dev/i18n/extract_default_translations.js index d32c62413e4ea..9a992d7406ef4 100644 --- a/src/dev/i18n/extract_default_translations.js +++ b/src/dev/i18n/extract_default_translations.js @@ -23,7 +23,6 @@ import { extractHtmlMessages, extractCodeMessages, extractPugMessages, - extractHandlebarsMessages, } from './extractors'; import { globAsync, readFileAsync, normalizePath } from './utils'; @@ -64,13 +63,13 @@ See .i18nrc.json for the list of supported namespaces.`) } export async function extractMessagesFromPathToMap(inputPath, targetMap, config, reporter) { - const entries = await globAsync('*.{js,jsx,pug,ts,tsx,html,hbs,handlebars}', { + const entries = await globAsync('*.{js,jsx,pug,ts,tsx,html}', { cwd: inputPath, matchBase: true, ignore: ['**/node_modules/**', '**/__tests__/**', '**/*.test.{js,jsx,ts,tsx}', '**/*.d.ts'], }); - const { htmlEntries, codeEntries, pugEntries, hbsEntries } = entries.reduce( + const { htmlEntries, codeEntries, pugEntries } = entries.reduce( (paths, entry) => { const resolvedPath = path.resolve(inputPath, entry); @@ -78,15 +77,13 @@ export async function extractMessagesFromPathToMap(inputPath, targetMap, config, paths.htmlEntries.push(resolvedPath); } else if (resolvedPath.endsWith('.pug')) { paths.pugEntries.push(resolvedPath); - } else if (resolvedPath.endsWith('.hbs') || resolvedPath.endsWith('.handlebars')) { - paths.hbsEntries.push(resolvedPath); } else { paths.codeEntries.push(resolvedPath); } return paths; }, - { htmlEntries: [], codeEntries: [], pugEntries: [], hbsEntries: [] } + { htmlEntries: [], codeEntries: [], pugEntries: [] } ); await Promise.all( @@ -94,7 +91,6 @@ export async function extractMessagesFromPathToMap(inputPath, targetMap, config, [htmlEntries, extractHtmlMessages], [codeEntries, extractCodeMessages], [pugEntries, extractPugMessages], - [hbsEntries, extractHandlebarsMessages], ].map(async ([entries, extractFunction]) => { const files = await Promise.all( filterEntries(entries, config.exclude).map(async entry => { diff --git a/src/dev/i18n/extractors/__snapshots__/handlebars.test.js.snap b/src/dev/i18n/extractors/__snapshots__/handlebars.test.js.snap deleted file mode 100644 index 2543e4dfd645a..0000000000000 --- a/src/dev/i18n/extractors/__snapshots__/handlebars.test.js.snap +++ /dev/null @@ -1,45 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`dev/i18n/extractors/handlebars extracts handlebars default messages 1`] = ` -Array [ - Array [ - "ui.id-1", - Object { - "description": "Message description", - "message": "Message text", - }, - ], -] -`; - -exports[`dev/i18n/extractors/handlebars throws on empty id 1`] = ` -Array [ - Array [ - [Error: Empty id argument in Handlebars i18n is not allowed.], - ], -] -`; - -exports[`dev/i18n/extractors/handlebars throws on missing defaultMessage property 1`] = ` -Array [ - Array [ - [Error: defaultMessage value in Handlebars i18n should be a string ("message-id").], - ], -] -`; - -exports[`dev/i18n/extractors/handlebars throws on wrong number of arguments 1`] = ` -Array [ - Array [ - [Error: Wrong number of arguments for handlebars i18n call.], - ], -] -`; - -exports[`dev/i18n/extractors/handlebars throws on wrong properties argument type 1`] = ` -Array [ - Array [ - [Error: Properties string in Handlebars i18n should be a string literal ("ui.id-1").], - ], -] -`; diff --git a/src/dev/i18n/extractors/handlebars.js b/src/dev/i18n/extractors/handlebars.js deleted file mode 100644 index 4ce9ba5f995d7..0000000000000 --- a/src/dev/i18n/extractors/handlebars.js +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 { formatJSString, checkValuesProperty } from '../utils'; -import { createFailError, isFailError } from '../../run'; -import { DEFAULT_MESSAGE_KEY, DESCRIPTION_KEY } from '../constants'; - -const HBS_REGEX = /(?<=\{\{)([\s\S]*?)(?=\}\})/g; -const TOKENS_REGEX = /[^'\s]+|(?:'([^'\\]|\\[\s\S])*')/g; - -/** - * Example: `'{{i18n 'message-id' '{"defaultMessage": "Message text"}'}}'` - */ -export function* extractHandlebarsMessages(buffer, reporter) { - for (const expression of buffer.toString().match(HBS_REGEX) || []) { - const tokens = expression.match(TOKENS_REGEX); - - const [functionName, idString, propertiesString] = tokens; - - if (functionName !== 'i18n') { - continue; - } - - if (tokens.length !== 3) { - reporter.report(createFailError(`Wrong number of arguments for handlebars i18n call.`)); - continue; - } - - if (!idString.startsWith(`'`) || !idString.endsWith(`'`)) { - reporter.report(createFailError(`Message id should be a string literal.`)); - continue; - } - - const messageId = formatJSString(idString.slice(1, -1)); - - if (!messageId) { - reporter.report(createFailError(`Empty id argument in Handlebars i18n is not allowed.`)); - continue; - } - - if (!propertiesString.startsWith(`'`) || !propertiesString.endsWith(`'`)) { - reporter.report( - createFailError( - `Properties string in Handlebars i18n should be a string literal ("${messageId}").` - ) - ); - continue; - } - - const properties = JSON.parse(propertiesString.slice(1, -1)); - - if (typeof properties.defaultMessage !== 'string') { - reporter.report( - createFailError( - `defaultMessage value in Handlebars i18n should be a string ("${messageId}").` - ) - ); - continue; - } - - if (properties[DESCRIPTION_KEY] != null && typeof properties[DESCRIPTION_KEY] !== 'string') { - reporter.report( - createFailError(`Description value in Handlebars i18n should be a string ("${messageId}").`) - ); - continue; - } - - const message = formatJSString(properties[DEFAULT_MESSAGE_KEY]); - const description = formatJSString(properties[DESCRIPTION_KEY]); - - if (!message) { - reporter.report( - createFailError(`Empty defaultMessage in Handlebars i18n is not allowed ("${messageId}").`) - ); - continue; - } - - const valuesObject = properties.values; - - if (valuesObject != null && typeof valuesObject !== 'object') { - reporter.report( - createFailError(`"values" value should be an object in Handlebars i18n ("${messageId}").`) - ); - continue; - } - - try { - checkValuesProperty(Object.keys(valuesObject || {}), message, messageId); - - yield [messageId, { message, description }]; - } catch (error) { - if (!isFailError(error)) { - throw error; - } - - reporter.report(error); - } - } -} diff --git a/src/dev/i18n/extractors/handlebars.test.js b/src/dev/i18n/extractors/handlebars.test.js deleted file mode 100644 index b1c51b4bf3a06..0000000000000 --- a/src/dev/i18n/extractors/handlebars.test.js +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 { extractHandlebarsMessages } from './handlebars'; - -const report = jest.fn(); - -describe('dev/i18n/extractors/handlebars', () => { - beforeEach(() => { - report.mockClear(); - }); - - test('extracts handlebars default messages', () => { - const source = Buffer.from(`\ -window.onload = function () { - (function next() { - var failure = function () { - failure = function () {}; - - var err = document.createElement('h1'); - err.style['color'] = 'white'; - err.innerText = '{{i18n 'ui.id-1' \ -'{"defaultMessage": "Message text", "description": "Message description"}'}}'; - - document.body.innerHTML = err.outerHTML; - } - }()); -}; -`); - - const actual = Array.from(extractHandlebarsMessages(source)); - expect(actual).toMatchSnapshot(); - }); - - test('throws on wrong number of arguments', () => { - const source = Buffer.from(`\ -window.onload = function () { - err.innerText = '{{i18n 'ui.id-1'}}'; -}; -`); - - expect(() => extractHandlebarsMessages(source, { report }).next()).not.toThrow(); - expect(report.mock.calls).toMatchSnapshot(); - }); - - test('throws on wrong properties argument type', () => { - const source = Buffer.from(`\ -window.onload = function () { - err.innerText = '{{i18n 'ui.id-1' propertiesJSONIdentifier}}'; -}; -`); - - expect(() => extractHandlebarsMessages(source, { report }).next()).not.toThrow(); - expect(report.mock.calls).toMatchSnapshot(); - }); - - test('throws on empty id', () => { - const source = Buffer.from(`\ -window.onload = function () { - err.innerText = '{{i18n '' '{"defaultMessage": "Message text", "description": "Message description"}'}}'; -}; -`); - - expect(() => extractHandlebarsMessages(source, { report }).next()).not.toThrow(); - expect(report.mock.calls).toMatchSnapshot(); - }); - - test('throws on missing defaultMessage property', () => { - const source = Buffer.from(`\ -window.onload = function () { - err.innerText = '{{i18n 'message-id' '{"description": "Message description"}'}}'; -}; -`); - - expect(() => extractHandlebarsMessages(source, { report }).next()).not.toThrow(); - expect(report.mock.calls).toMatchSnapshot(); - }); -}); diff --git a/src/dev/i18n/extractors/index.js b/src/dev/i18n/extractors/index.js index 72e4378d3dfad..48e90de6c6d49 100644 --- a/src/dev/i18n/extractors/index.js +++ b/src/dev/i18n/extractors/index.js @@ -18,6 +18,5 @@ */ export { extractCodeMessages } from './code'; -export { extractHandlebarsMessages } from './handlebars'; export { extractHtmlMessages } from './html'; export { extractPugMessages } from './pug'; diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index 3093af827d70e..4509af6ac5555 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -33,6 +33,7 @@ export default { '/src/setup_node_env', '/packages', '/src/test_utils', + '/test/functional/services/remote', ], collectCoverageFrom: [ 'packages/kbn-ui-framework/src/components/**/*.js', diff --git a/src/dev/typescript/exec_in_projects.ts b/src/dev/typescript/exec_in_projects.ts index 3bb7dcbeea4f5..12e64e63ab3c4 100644 --- a/src/dev/typescript/exec_in_projects.ts +++ b/src/dev/typescript/exec_in_projects.ts @@ -64,7 +64,9 @@ export function execInProjects( for (const e of error.errors) { if (e instanceof ProjectFailure) { log.write(''); - log.error(`${e.project.name} failed\n${e.error.stdout}`); + // stdout contains errors from tsc + // stderr conatins tsc crash report + log.error(`${e.project.name} failed\n${e.error.stdout || e.error.stderr}`); } else { log.error(e); } diff --git a/src/dev/typescript/projects.ts b/src/dev/typescript/projects.ts index f7d111158fa34..540441ab6b8de 100644 --- a/src/dev/typescript/projects.ts +++ b/src/dev/typescript/projects.ts @@ -25,9 +25,9 @@ import { Project } from './project'; export const PROJECTS = [ new Project(resolve(REPO_ROOT, 'tsconfig.json')), + new Project(resolve(REPO_ROOT, 'test/tsconfig.json'), 'kibana/test'), new Project(resolve(REPO_ROOT, 'x-pack/tsconfig.json')), new Project(resolve(REPO_ROOT, 'x-pack/test/tsconfig.json'), 'x-pack/test'), - new Project(resolve(REPO_ROOT, 'test/tsconfig.json')), // NOTE: using glob.sync rather than glob-all or globby // because it takes less than 10 ms, while the other modules diff --git a/src/es_archiver/es_archiver.d.ts b/src/es_archiver/es_archiver.d.ts new file mode 100644 index 0000000000000..c50ae19d99cbf --- /dev/null +++ b/src/es_archiver/es_archiver.d.ts @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { ToolingLog } from '@kbn/dev-utils'; +import { Client } from 'elasticsearch'; +import { createStats } from './lib/stats'; + +export type JsonStats = ReturnType['toJSON']>; + +export class EsArchiver { + constructor(options: { client: Client; dataDir: string; log: ToolingLog; kibanaUrl: string }); + public save( + name: string, + indices: string | string[], + options?: { raw?: boolean } + ): Promise; + public load(name: string, options?: { skipExisting?: boolean }): Promise; + public unload(name: string): Promise; + public rebuildAll(): Promise; + public edit(prefix: string, handler: () => Promise): Promise; + public loadIfNeeded(name: string): Promise; + public emptyKibanaIndex(): Promise; +} diff --git a/src/legacy/core_plugins/elasticsearch/lib/default_api_version.js b/src/es_archiver/index.d.ts similarity index 94% rename from src/legacy/core_plugins/elasticsearch/lib/default_api_version.js rename to src/es_archiver/index.d.ts index 5b7d77e29c71e..f7a579a98a42d 100644 --- a/src/legacy/core_plugins/elasticsearch/lib/default_api_version.js +++ b/src/es_archiver/index.d.ts @@ -17,4 +17,4 @@ * under the License. */ -export const DEFAULT_API_VERSION = 'master'; +export { EsArchiver } from './es_archiver'; diff --git a/src/es_archiver/lib/stats.js b/src/es_archiver/lib/stats.js deleted file mode 100644 index 1101c8e06563c..0000000000000 --- a/src/es_archiver/lib/stats.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 { cloneDeep } from 'lodash'; - -export function createStats(name, log) { - const info = (msg, ...args) => log.info(`[${name}] ${msg}`, ...args); - const debug = (msg, ...args) => log.debug(`[${name}] ${msg}`, ...args); - - const indices = {}; - const getOrCreate = index => { - if (!indices[index]) { - indices[index] = { - skipped: false, - deleted: false, - created: false, - archived: false, - waitForSnapshot: 0, - configDocs: { - upgraded: 0, - tagged: 0, - upToDate: 0, - }, - docs: { - indexed: 0, - archived: 0, - } - }; - } - return indices[index]; - }; - - class Stats { - skippedIndex(index) { - getOrCreate(index).skipped = true; - info('Skipped restore for existing index %j', index); - } - - waitingForInProgressSnapshot(index) { - getOrCreate(index).waitForSnapshot += 1; - info('Waiting for snapshot of %j to complete', index); - } - - deletedIndex(index) { - getOrCreate(index).deleted = true; - info('Deleted existing index %j', index); - } - - createdIndex(index, metadata) { - getOrCreate(index).created = true; - info('Created index %j', index); - Object.keys(metadata || {}).forEach(name => { - debug('%j %s %j', index, name, metadata[name]); - }); - } - - archivedIndex(index, metadata) { - getOrCreate(index).archived = true; - info('Archived %j', index); - Object.keys(metadata || {}).forEach(name => { - debug('%j %s %j', index, name, metadata[name]); - }); - } - - indexedDoc(index) { - getOrCreate(index).docs.indexed += 1; - } - - archivedDoc(index) { - getOrCreate(index).docs.archived += 1; - } - - toJSON() { - return cloneDeep(indices); - } - - forEachIndex(fn) { - const clone = this.toJSON(); - Object.keys(clone).forEach(index => { - fn(index, clone[index]); - }); - } - } - - return new Stats(); -} diff --git a/src/es_archiver/lib/stats.ts b/src/es_archiver/lib/stats.ts new file mode 100644 index 0000000000000..965981af3dc84 --- /dev/null +++ b/src/es_archiver/lib/stats.ts @@ -0,0 +1,153 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { ToolingLog } from '@kbn/dev-utils'; +import { cloneDeep } from 'lodash'; + +export interface IndexStats { + skipped: boolean; + deleted: boolean; + created: boolean; + archived: boolean; + waitForSnapshot: number; + configDocs: { + upgraded: number; + tagged: number; + upToDate: number; + }; + docs: { + indexed: number; + archived: number; + }; +} + +export function createStats(name: string, log: ToolingLog) { + const info = (msg: string, ...args: any[]) => log.info(`[${name}] ${msg}`, ...args); + const debug = (msg: string, ...args: any[]) => log.debug(`[${name}] ${msg}`, ...args); + + const indices: Record = {}; + const getOrCreate = (index: string) => { + if (!indices[index]) { + indices[index] = { + skipped: false, + deleted: false, + created: false, + archived: false, + waitForSnapshot: 0, + configDocs: { + upgraded: 0, + tagged: 0, + upToDate: 0, + }, + docs: { + indexed: 0, + archived: 0, + }, + }; + } + return indices[index]; + }; + + return new class Stats { + /** + * Record that an index was not restored because it already existed + * @param index + */ + public skippedIndex(index: string) { + getOrCreate(index).skipped = true; + info('Skipped restore for existing index %j', index); + } + + /** + * Record that the esArchiver waited for an index that was in the middle of being snapshotted + * @param index + */ + public waitingForInProgressSnapshot(index: string) { + getOrCreate(index).waitForSnapshot += 1; + info('Waiting for snapshot of %j to complete', index); + } + + /** + * Record that an index was deleted + * @param index + */ + public deletedIndex(index: string) { + getOrCreate(index).deleted = true; + info('Deleted existing index %j', index); + } + + /** + * Record that an index was created + * @param index + */ + public createdIndex(index: string, metadata: Record = {}) { + getOrCreate(index).created = true; + info('Created index %j', index); + Object.keys(metadata).forEach(key => { + debug('%j %s %j', index, key, metadata[key]); + }); + } + + /** + * Record that an index was written to the archives + * @param index + */ + public archivedIndex(index: string, metadata: Record = {}) { + getOrCreate(index).archived = true; + info('Archived %j', index); + Object.keys(metadata).forEach(key => { + debug('%j %s %j', index, key, metadata[key]); + }); + } + + /** + * Record that a document was written to elasticsearch + * @param index + */ + public indexedDoc(index: string) { + getOrCreate(index).docs.indexed += 1; + } + + /** + * Record that a document was added to the archives + * @param index + */ + public archivedDoc(index: string) { + getOrCreate(index).docs.archived += 1; + } + + /** + * Get a plain object version of the stats by index + */ + public toJSON() { + return cloneDeep(indices); + } + + /** + * Iterate the status for each index + * @param fn + */ + public forEachIndex(fn: (index: string, stats: IndexStats) => void) { + const clone = this.toJSON(); + Object.keys(clone).forEach(index => { + fn(index, clone[index]); + }); + } + }(); +} diff --git a/src/fixtures/field_mapping.js b/src/fixtures/field_mapping.js index 0f389c6057b1f..08fcb53a0a860 100644 --- a/src/fixtures/field_mapping.js +++ b/src/fixtures/field_mapping.js @@ -76,4 +76,4 @@ export default { } } } -}; \ No newline at end of file +}; diff --git a/src/fixtures/mapping_with_dupes.js b/src/fixtures/mapping_with_dupes.js index 79e544a0ccc6c..692c6c6f35ade 100644 --- a/src/fixtures/mapping_with_dupes.js +++ b/src/fixtures/mapping_with_dupes.js @@ -54,4 +54,4 @@ export default { } } } -}; \ No newline at end of file +}; diff --git a/src/fixtures/search_response.js b/src/fixtures/search_response.js index 1159f8ccffbf3..a4dd51fd95a55 100644 --- a/src/fixtures/search_response.js +++ b/src/fixtures/search_response.js @@ -32,4 +32,4 @@ export default { max_score: 1.0, hits: hits } -}; \ No newline at end of file +}; diff --git a/src/functional_test_runner/cli.js b/src/functional_test_runner/cli.js index 94892451155f8..9414dcfe1cfd9 100644 --- a/src/functional_test_runner/cli.js +++ b/src/functional_test_runner/cli.js @@ -75,7 +75,6 @@ const functionalTestRunner = createFunctionalTestRunner({ bail: cmd.bail, grep: cmd.grep, invert: cmd.invert, - require: `ts-node/register --project tests/tsconfig.json -r tsconfig-paths/register -T "test/**/*.{ts,js}"` }, suiteTags: { include: cmd.includeTag, diff --git a/src/functional_test_runner/lib/config/config.js b/src/functional_test_runner/lib/config/config.ts similarity index 54% rename from src/functional_test_runner/lib/config/config.js rename to src/functional_test_runner/lib/config/config.ts index 302619561e870..9819f23a656bc 100644 --- a/src/functional_test_runner/lib/config/config.js +++ b/src/functional_test_runner/lib/config/config.ts @@ -17,20 +17,27 @@ * under the License. */ -import { get, has, cloneDeep } from 'lodash'; +import { Schema } from 'joi'; +import { cloneDeep, get, has } from 'lodash'; + +// @ts-ignore internal lodash module is not typed import toPath from 'lodash/internal/toPath'; import { schema } from './schema'; const $values = Symbol('values'); +interface Options { + settings?: Record; + primary?: boolean; + path: string; +} + export class Config { - constructor(options = {}) { - const { - settings = {}, - primary = false, - path, - } = options; + private [$values]: Record; + + constructor(options: Options) { + const { settings = {}, primary = false, path = null } = options || {}; if (!path) { throw new TypeError('path is a required option'); @@ -41,38 +48,52 @@ export class Config { context: { primary: !!primary, path, - } + }, }); - if (error) throw error; + if (error) { + throw error; + } + this[$values] = value; } - has(key) { - function recursiveHasCheck(path, values, schema) { - if (!schema._inner) return false; + public has(key: string) { + function recursiveHasCheck( + remainingPath: string[], + values: Record, + childSchema: any + ): boolean { + if (!childSchema._inner) { + return false; + } // normalize child and pattern checks so we can iterate the checks in a single loop - const checks = [].concat( + const checks: Array<{ test: (k: string) => boolean; schema: Schema }> = [ // match children first, they have priority - (schema._inner.children || []).map(child => ({ - test: key => child.key === key, - schema: child.schema + ...(childSchema._inner.children || []).map((child: { key: string; schema: Schema }) => ({ + test: (k: string) => child.key === k, + schema: child.schema, })), + // match patterns on any key that doesn't match an explicit child - (schema._inner.patterns || []).map(pattern => ({ - test: key => pattern.regex.test(key) && has(values, key), - schema: pattern.rule - })) - ); + ...(childSchema._inner.patterns || []).map((pattern: { regex: RegExp; rule: Schema }) => ({ + test: (k: string) => pattern.regex.test(k) && has(values, k), + schema: pattern.rule, + })), + ]; for (const check of checks) { - if (!check.test(path[0])) { + if (!check.test(remainingPath[0])) { continue; } - if (path.length > 1) { - return recursiveHasCheck(path.slice(1), get(values, path[0]), check.schema); + if (remainingPath.length > 1) { + return recursiveHasCheck( + remainingPath.slice(1), + get(values, remainingPath[0]), + check.schema + ); } return true; @@ -82,16 +103,18 @@ export class Config { } const path = toPath(key); - if (!path.length) return true; + if (!path.length) { + return true; + } return recursiveHasCheck(path, this[$values], schema); } - get(key, defaultValue) { + public get(key: string, defaultValue?: any) { if (!this.has(key)) { throw new Error(`Unknown config key "${key}"`); } - return cloneDeep(get(this[$values], key, defaultValue), (v) => { + return cloneDeep(get(this[$values], key, defaultValue), v => { if (typeof v === 'function') { return v; } diff --git a/src/functional_test_runner/lib/config/schema.js b/src/functional_test_runner/lib/config/schema.js deleted file mode 100644 index 89cf0318fd837..0000000000000 --- a/src/functional_test_runner/lib/config/schema.js +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 { resolve, dirname } from 'path'; - -import Joi from 'joi'; - -// valid pattern for ID -// enforced camel-case identifiers for consistency -const ID_PATTERN = /^[a-zA-Z0-9_]+$/; -const INSPECTING = ( - process.execArgv.includes('--inspect') || - process.execArgv.includes('--inspect-brk') -); - -const urlPartsSchema = () => Joi.object().keys({ - protocol: Joi.string().valid('http', 'https').default('http'), - hostname: Joi.string().hostname().default('localhost'), - port: Joi.number(), - auth: Joi.string().regex(/^[^:]+:.+$/, 'username and password separated by a colon'), - username: Joi.string(), - password: Joi.string(), - pathname: Joi.string().regex(/^\//, 'start with a /'), - hash: Joi.string().regex(/^\//, 'start with a /') -}).default(); - -const appUrlPartsSchema = () => Joi.object().keys({ - pathname: Joi.string().regex(/^\//, 'start with a /'), - hash: Joi.string().regex(/^\//, 'start with a /') -}).default(); - -const defaultRelativeToConfigPath = path => { - const makeDefault = (locals, options) => ( - resolve(dirname(options.context.path), path) - ); - makeDefault.description = `/${path}`; - return makeDefault; -}; - -export const schema = Joi.object().keys({ - testFiles: Joi.array().items(Joi.string()).when('$primary', { - is: true, - then: Joi.required(), - otherwise: Joi.default([]), - }), - - excludeTestFiles: Joi.array().items(Joi.string()).default([]), - - suiteTags: Joi.object().keys({ - include: Joi.array().items(Joi.string()).default([]), - exclude: Joi.array().items(Joi.string()).default([]), - }).default(), - - services: Joi.object().pattern( - ID_PATTERN, - Joi.func().required() - ).default(), - - pageObjects: Joi.object().pattern( - ID_PATTERN, - Joi.func().required() - ).default(), - - timeouts: Joi.object().keys({ - find: Joi.number().default(10000), - try: Joi.number().default(120000), - waitFor: Joi.number().default(20000), - esRequestTimeout: Joi.number().default(30000), - kibanaStabilize: Joi.number().default(15000), - navigateStatusPageCheck: Joi.number().default(250), - - // Many of our tests use the `exists` functions to determine where the user is. For - // example, you'll see a lot of code like: - // if (!testSubjects.exists('someElementOnPageA')) { - // navigateToPageA(); - // } - // If the element doesn't exist, selenium would wait up to defaultFindTimeout for it to - // appear. Because there are many times when we expect it to not be there, we don't want - // to wait the full amount of time, or it would greatly slow our tests down. We used to have - // this value at 1 second, but this caused flakiness because sometimes the element was deemed missing - // only because the page hadn't finished loading. - // The best path forward it to prefer functions like `testSubjects.existOrFail` or - // `testSubjects.missingOrFail` instead of just the `exists` checks, and be deterministic about - // where your user is and what they should click next. - waitForExists: Joi.number().default(2500), - }).default(), - - mochaOpts: Joi.object().keys({ - bail: Joi.boolean().default(false), - grep: Joi.string(), - invert: Joi.boolean().default(false), - slow: Joi.number().default(30000), - timeout: Joi.number().default(INSPECTING ? Infinity : 360000), - ui: Joi.string().default('bdd'), - require: Joi.string().default('') - }).default(), - - updateBaselines: Joi.boolean().default(false), - - junit: Joi.object().keys({ - enabled: Joi.boolean().default(!!process.env.CI), - reportName: Joi.string(), - rootDirectory: Joi.string(), - }).default(), - - mochaReporter: Joi.object().keys({ - captureLogOutput: Joi.boolean().default(!!process.env.CI), - }).default(), - - users: Joi.object().pattern( - ID_PATTERN, - Joi.object().keys({ - username: Joi.string().required(), - password: Joi.string().required(), - }).required() - ), - - servers: Joi.object().keys({ - kibana: urlPartsSchema(), - elasticsearch: urlPartsSchema(), - }).default(), - - esTestCluster: Joi.object().keys({ - license: Joi.string().default('oss'), - from: Joi.string().default('snapshot'), - serverArgs: Joi.array(), - dataArchive: Joi.string(), - }).default(), - - kbnTestServer: Joi.object().keys({ - buildArgs: Joi.array(), - sourceArgs: Joi.array(), - serverArgs: Joi.array(), - }).default(), - - chromedriver: Joi.object().keys({ - url: Joi.string().uri({ scheme: /https?/ }).default('http://localhost:9515') - }).default(), - - firefoxdriver: Joi.object().keys({ - url: Joi.string().uri({ scheme: /https?/ }).default('http://localhost:2828') - }).default(), - - - // definition of apps that work with `common.navigateToApp()` - apps: Joi.object().pattern( - ID_PATTERN, - appUrlPartsSchema() - ).default(), - - // settings for the esArchiver module - esArchiver: Joi.object().keys({ - directory: Joi.string().default(defaultRelativeToConfigPath('fixtures/es_archiver')), - }).default(), - - // settings for the kibanaServer.uiSettings module - uiSettings: Joi.object().keys({ - defaults: Joi.object().unknown(true) - }).default(), - - // settings for the screenshots module - screenshots: Joi.object().keys({ - directory: Joi.string().default(defaultRelativeToConfigPath('screenshots')) - }).default(), - - // settings for the failureDebugging module - failureDebugging: Joi.object().keys({ - htmlDirectory: Joi.string().default(defaultRelativeToConfigPath('failure_debug/html')) - }).default(), - - // settings for the find service - layout: Joi.object().keys({ - fixedHeaderHeight: Joi.number().default(50), - }).default(), -}).default(); diff --git a/src/functional_test_runner/lib/config/schema.ts b/src/functional_test_runner/lib/config/schema.ts new file mode 100644 index 0000000000000..8610a8d3bdbcd --- /dev/null +++ b/src/functional_test_runner/lib/config/schema.ts @@ -0,0 +1,237 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { dirname, resolve } from 'path'; + +import Joi from 'joi'; + +// valid pattern for ID +// enforced camel-case identifiers for consistency +const ID_PATTERN = /^[a-zA-Z0-9_]+$/; +const INSPECTING = + process.execArgv.includes('--inspect') || process.execArgv.includes('--inspect-brk'); + +const urlPartsSchema = () => + Joi.object() + .keys({ + protocol: Joi.string() + .valid('http', 'https') + .default('http'), + hostname: Joi.string() + .hostname() + .default('localhost'), + port: Joi.number(), + auth: Joi.string().regex(/^[^:]+:.+$/, 'username and password separated by a colon'), + username: Joi.string(), + password: Joi.string(), + pathname: Joi.string().regex(/^\//, 'start with a /'), + hash: Joi.string().regex(/^\//, 'start with a /'), + }) + .default(); + +const appUrlPartsSchema = () => + Joi.object() + .keys({ + pathname: Joi.string().regex(/^\//, 'start with a /'), + hash: Joi.string().regex(/^\//, 'start with a /'), + }) + .default(); + +const defaultRelativeToConfigPath = (path: string) => { + const makeDefault: any = (_: any, options: any) => resolve(dirname(options.context.path), path); + makeDefault.description = `/${path}`; + return makeDefault; +}; + +export const schema = Joi.object() + .keys({ + testFiles: Joi.array() + .items(Joi.string()) + .when('$primary', { + is: true, + then: Joi.required(), + otherwise: Joi.any().default([]), + }), + + excludeTestFiles: Joi.array() + .items(Joi.string()) + .default([]), + + suiteTags: Joi.object() + .keys({ + include: Joi.array() + .items(Joi.string()) + .default([]), + exclude: Joi.array() + .items(Joi.string()) + .default([]), + }) + .default(), + + services: Joi.object() + .pattern(ID_PATTERN, Joi.func().required()) + .default(), + + pageObjects: Joi.object() + .pattern(ID_PATTERN, Joi.func().required()) + .default(), + + timeouts: Joi.object() + .keys({ + find: Joi.number().default(10000), + try: Joi.number().default(120000), + waitFor: Joi.number().default(20000), + esRequestTimeout: Joi.number().default(30000), + kibanaStabilize: Joi.number().default(15000), + navigateStatusPageCheck: Joi.number().default(250), + + // Many of our tests use the `exists` functions to determine where the user is. For + // example, you'll see a lot of code like: + // if (!testSubjects.exists('someElementOnPageA')) { + // navigateToPageA(); + // } + // If the element doesn't exist, selenium would wait up to defaultFindTimeout for it to + // appear. Because there are many times when we expect it to not be there, we don't want + // to wait the full amount of time, or it would greatly slow our tests down. We used to have + // this value at 1 second, but this caused flakiness because sometimes the element was deemed missing + // only because the page hadn't finished loading. + // The best path forward it to prefer functions like `testSubjects.existOrFail` or + // `testSubjects.missingOrFail` instead of just the `exists` checks, and be deterministic about + // where your user is and what they should click next. + waitForExists: Joi.number().default(2500), + }) + .default(), + + mochaOpts: Joi.object() + .keys({ + bail: Joi.boolean().default(false), + grep: Joi.string(), + invert: Joi.boolean().default(false), + slow: Joi.number().default(30000), + timeout: Joi.number().default(INSPECTING ? Infinity : 360000), + ui: Joi.string().default('bdd'), + }) + .default(), + + updateBaselines: Joi.boolean().default(false), + + junit: Joi.object() + .keys({ + enabled: Joi.boolean().default(!!process.env.CI), + reportName: Joi.string(), + }) + .default(), + + mochaReporter: Joi.object() + .keys({ + captureLogOutput: Joi.boolean().default(!!process.env.CI), + }) + .default(), + + users: Joi.object().pattern( + ID_PATTERN, + Joi.object() + .keys({ + username: Joi.string().required(), + password: Joi.string().required(), + }) + .required() + ), + + servers: Joi.object() + .keys({ + kibana: urlPartsSchema(), + elasticsearch: urlPartsSchema(), + }) + .default(), + + esTestCluster: Joi.object() + .keys({ + license: Joi.string().default('oss'), + from: Joi.string().default('snapshot'), + serverArgs: Joi.array(), + dataArchive: Joi.string(), + }) + .default(), + + kbnTestServer: Joi.object() + .keys({ + buildArgs: Joi.array(), + sourceArgs: Joi.array(), + serverArgs: Joi.array(), + }) + .default(), + + chromedriver: Joi.object() + .keys({ + url: Joi.string() + .uri({ scheme: /https?/ }) + .default('http://localhost:9515'), + }) + .default(), + + firefoxdriver: Joi.object() + .keys({ + url: Joi.string() + .uri({ scheme: /https?/ }) + .default('http://localhost:2828'), + }) + .default(), + + // definition of apps that work with `common.navigateToApp()` + apps: Joi.object() + .pattern(ID_PATTERN, appUrlPartsSchema()) + .default(), + + // settings for the esArchiver module + esArchiver: Joi.object() + .keys({ + directory: Joi.string().default(defaultRelativeToConfigPath('fixtures/es_archiver')), + }) + .default(), + + // settings for the kibanaServer.uiSettings module + uiSettings: Joi.object() + .keys({ + defaults: Joi.object().unknown(true), + }) + .default(), + + // settings for the screenshots module + screenshots: Joi.object() + .keys({ + directory: Joi.string().default(defaultRelativeToConfigPath('screenshots')), + }) + .default(), + + // settings for the failureDebugging module + failureDebugging: Joi.object() + .keys({ + htmlDirectory: Joi.string().default(defaultRelativeToConfigPath('failure_debug/html')), + }) + .default(), + + // settings for the find service + layout: Joi.object() + .keys({ + fixedHeaderHeight: Joi.number().default(50), + }) + .default(), + }) + .default(); diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/extended_stats_types.js b/src/functional_test_runner/lib/index.d.ts similarity index 90% rename from src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/extended_stats_types.js rename to src/functional_test_runner/lib/index.d.ts index e206a1ce5c23e..6c71239d17bc9 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/extended_stats_types.js +++ b/src/functional_test_runner/lib/index.d.ts @@ -17,10 +17,5 @@ * under the License. */ -export default [ - 'std_deviation', - 'variance', - 'sum_of_squares' -]; - - +export { Config } from './config/config'; +export { Lifecycle } from './lifecycle'; diff --git a/src/functional_test_runner/lib/lifecycle.js b/src/functional_test_runner/lib/lifecycle.ts similarity index 66% rename from src/functional_test_runner/lib/lifecycle.js rename to src/functional_test_runner/lib/lifecycle.ts index 0f05eb45871da..97b7a5538fe40 100644 --- a/src/functional_test_runner/lib/lifecycle.js +++ b/src/functional_test_runner/lib/lifecycle.ts @@ -17,31 +17,34 @@ * under the License. */ +type Listener = (...args: any[]) => Promise | void; +export type Lifecycle = ReturnType; + export function createLifecycle() { const listeners = { - beforeLoadTests: [], - beforeTests: [], - beforeTestSuite: [], - beforeEachTest: [], - afterTestSuite: [], - testFailure: [], - testHookFailure: [], - cleanup: [], - phaseStart: [], - phaseEnd: [], + beforeLoadTests: [] as Listener[], + beforeTests: [] as Listener[], + beforeTestSuite: [] as Listener[], + beforeEachTest: [] as Listener[], + afterTestSuite: [] as Listener[], + testFailure: [] as Listener[], + testHookFailure: [] as Listener[], + cleanup: [] as Listener[], + phaseStart: [] as Listener[], + phaseEnd: [] as Listener[], }; - class Lifecycle { - on(name, fn) { + return { + on(name: keyof typeof listeners, fn: Listener) { if (!listeners[name]) { throw new TypeError(`invalid lifecycle event "${name}"`); } listeners[name].push(fn); return this; - } + }, - async trigger(name, ...args) { + async trigger(name: keyof typeof listeners, ...args: any[]) { if (!listeners[name]) { throw new TypeError(`invalid lifecycle event "${name}"`); } @@ -51,16 +54,12 @@ export function createLifecycle() { await this.trigger('phaseStart', name); } - await Promise.all(listeners[name].map( - async fn => await fn(...args) - )); + await Promise.all(listeners[name].map(async fn => await fn(...args))); } finally { if (name !== 'phaseStart' && name !== 'phaseEnd') { await this.trigger('phaseEnd', name); } } - } - } - - return new Lifecycle(); + }, + }; } diff --git a/src/functional_test_runner/lib/mocha/reporter/reporter.js b/src/functional_test_runner/lib/mocha/reporter/reporter.js index 363fbee500a53..386411631c155 100644 --- a/src/functional_test_runner/lib/mocha/reporter/reporter.js +++ b/src/functional_test_runner/lib/mocha/reporter/reporter.js @@ -54,7 +54,6 @@ export function MochaReporterProvider({ getService }) { if (config.get('junit.enabled') && config.get('junit.reportName')) { setupJUnitReportGeneration(runner, { reportName: config.get('junit.reportName'), - rootDirectory: config.get('junit.rootDirectory') }); } } diff --git a/src/functional_test_runner/lib/providers/provider_collection.js b/src/functional_test_runner/lib/providers/provider_collection.js index dba2466c9868e..259b762c1f207 100644 --- a/src/functional_test_runner/lib/providers/provider_collection.js +++ b/src/functional_test_runner/lib/providers/provider_collection.js @@ -105,7 +105,7 @@ export class ProviderCollection { instance = createAsyncInstance(type, name, instance); } - if (name !== '__leadfoot__' && name !== 'log' && name !== 'config' && instance && typeof instance === 'object') { + if (name !== '__webdriver__' && name !== 'log' && name !== 'config' && instance && typeof instance === 'object') { instance = createVerboseInstance( this._log, type === 'PageObject' ? `PageObjects.${name}` : name, diff --git a/test/typings/wrapper.ts b/src/functional_test_runner/types.ts similarity index 80% rename from test/typings/wrapper.ts rename to src/functional_test_runner/types.ts index 69a6f7547028c..0d53838b1e16c 100644 --- a/test/typings/wrapper.ts +++ b/src/functional_test_runner/types.ts @@ -17,7 +17,11 @@ * under the License. */ -export interface TestWrapper { - getService(service: string): any; - getPageObjects(pages: string[]): { [name: string]: any }; +import { ToolingLog } from '@kbn/dev-utils'; +import { Config, Lifecycle } from './lib'; + +export interface DefaultServiceProviders { + config(): Config; + log(): ToolingLog; + lifecycle(): Lifecycle; } diff --git a/src/legacy/core_plugins/console/api_server/es_6_0/query/index.js b/src/legacy/core_plugins/console/api_server/es_6_0/query/index.js index 8366478afe1ac..cf5306ce925ba 100644 --- a/src/legacy/core_plugins/console/api_server/es_6_0/query/index.js +++ b/src/legacy/core_plugins/console/api_server/es_6_0/query/index.js @@ -17,4 +17,4 @@ * under the License. */ -export { queryDsl as default } from './dsl'; \ No newline at end of file +export { queryDsl as default } from './dsl'; diff --git a/src/legacy/core_plugins/console/api_server/es_6_0/reindex.js b/src/legacy/core_plugins/console/api_server/es_6_0/reindex.js index 618c1f4dcaf0d..b7bd2c0608b64 100644 --- a/src/legacy/core_plugins/console/api_server/es_6_0/reindex.js +++ b/src/legacy/core_plugins/console/api_server/es_6_0/reindex.js @@ -65,4 +65,4 @@ export default function (api) { 'script': { __scope_link: 'GLOBAL.script' }, } }); -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/console/api_server/spec/index.js b/src/legacy/core_plugins/console/api_server/spec/index.js index 84607e18fe674..601c5e6153e2c 100644 --- a/src/legacy/core_plugins/console/api_server/spec/index.js +++ b/src/legacy/core_plugins/console/api_server/spec/index.js @@ -56,4 +56,4 @@ export function getSpec() { export function addExtensionSpecFilePath(extensionSpecFilePath) { extensionSpecFilePaths.push(extensionSpecFilePath); -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/console/index.js b/src/legacy/core_plugins/console/index.js index c22e8d0d945dc..2a314c873de50 100644 --- a/src/legacy/core_plugins/console/index.js +++ b/src/legacy/core_plugins/console/index.js @@ -18,13 +18,14 @@ */ import Boom from 'boom'; +import { first } from 'rxjs/operators'; import { resolve, join, sep } from 'path'; import url from 'url'; -import { has, isEmpty, head } from 'lodash'; +import { has, isEmpty, head, pick } from 'lodash'; import { resolveApi } from './api_server/server'; import { addExtensionSpecFilePath } from './api_server/spec'; -import setHeaders from '../elasticsearch/lib/set_headers'; +import { setHeaders } from './server/set_headers'; import { ProxyConfigCollection, @@ -32,10 +33,26 @@ import { createProxyRoute } from './server'; +function filterHeaders(originalHeaders, headersToKeep) { + const normalizeHeader = function (header) { + if (!header) { + return ''; + } + header = header.toString(); + return header.trim().toLowerCase(); + }; + + // Normalize list of headers we want to allow in upstream request + const headersToKeepNormalized = headersToKeep.map(normalizeHeader); + + return pick(originalHeaders, headersToKeepNormalized); +} + export default function (kibana) { const modules = resolve(__dirname, 'public/webpackShims/'); const src = resolve(__dirname, 'public/src/'); + let defaultVars; const apps = []; return new kibana.Plugin({ id: 'console', @@ -79,24 +96,29 @@ export default function (kibana) { ]; }, - init: function (server, options) { + async init(server, options) { server.expose('addExtensionSpecFilePath', addExtensionSpecFilePath); if (options.ssl && options.ssl.verify) { throw new Error('sense.ssl.verify is no longer supported.'); } const config = server.config(); - const { filterHeaders } = server.plugins.elasticsearch; + const legacyEsConfig = await server.core.elasticsearch.legacy.config$.pipe(first()).toPromise(); const proxyConfigCollection = new ProxyConfigCollection(options.proxyConfig); const proxyPathFilters = options.proxyFilter.map(str => new RegExp(str)); + defaultVars = { + elasticsearchUrl: url.format( + Object.assign(url.parse(head(legacyEsConfig.hosts)), { auth: false }) + ) + }; + server.route(createProxyRoute({ - baseUrl: head(config.get('elasticsearch.hosts')), + baseUrl: head(legacyEsConfig.hosts), pathFilters: proxyPathFilters, getConfigForReq(req, uri) { - const whitelist = config.get('elasticsearch.requestHeadersWhitelist'); - const filteredHeaders = filterHeaders(req.headers, whitelist); - const headers = setHeaders(filteredHeaders, config.get('elasticsearch.customHeaders')); + const filteredHeaders = filterHeaders(req.headers, legacyEsConfig.requestHeadersWhitelist); + const headers = setHeaders(filteredHeaders, legacyEsConfig.customHeaders); if (!isEmpty(config.get('console.proxyConfig'))) { return { @@ -106,7 +128,7 @@ export default function (kibana) { } return { - ...getElasticsearchProxyConfig(server), + ...getElasticsearchProxyConfig(legacyEsConfig), headers, }; } @@ -132,20 +154,7 @@ export default function (kibana) { devTools: ['plugins/console/console'], styleSheetPaths: resolve(__dirname, 'public/index.scss'), - injectDefaultVars(server) { - return { - elasticsearchUrl: url.format( - Object.assign( - url.parse( - head( - server.config().get('elasticsearch.hosts') - ) - ), - { auth: false } - ) - ) - }; - }, + injectDefaultVars: () => defaultVars, noParse: [ join(modules, 'ace' + sep), diff --git a/src/legacy/core_plugins/console/public/src/autocomplete/components/conditional_proxy.js b/src/legacy/core_plugins/console/public/src/autocomplete/components/conditional_proxy.js index 9ee233d54c20a..04dc46b6dc278 100644 --- a/src/legacy/core_plugins/console/public/src/autocomplete/components/conditional_proxy.js +++ b/src/legacy/core_plugins/console/public/src/autocomplete/components/conditional_proxy.js @@ -40,4 +40,4 @@ export class ConditionalProxy extends SharedComponent { return false; } } -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/console/public/src/autocomplete/components/global_only_component.js b/src/legacy/core_plugins/console/public/src/autocomplete/components/global_only_component.js index ee50e3634cc61..6ac7da79a7a87 100644 --- a/src/legacy/core_plugins/console/public/src/autocomplete/components/global_only_component.js +++ b/src/legacy/core_plugins/console/public/src/autocomplete/components/global_only_component.js @@ -43,4 +43,4 @@ export class GlobalOnlyComponent extends SharedComponent { return result; } -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/console/public/src/autocomplete/components/index_autocomplete_component.js b/src/legacy/core_plugins/console/public/src/autocomplete/components/index_autocomplete_component.js index ec1cfc60f9064..33e27852caff2 100644 --- a/src/legacy/core_plugins/console/public/src/autocomplete/components/index_autocomplete_component.js +++ b/src/legacy/core_plugins/console/public/src/autocomplete/components/index_autocomplete_component.js @@ -40,4 +40,4 @@ export class IndexAutocompleteComponent extends ListComponent { getContextKey() { return 'indices'; } -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/console/public/src/autocomplete/components/template_autocomplete_component.js b/src/legacy/core_plugins/console/public/src/autocomplete/components/template_autocomplete_component.js index 41ffaa5047479..e6cae3f1710bc 100644 --- a/src/legacy/core_plugins/console/public/src/autocomplete/components/template_autocomplete_component.js +++ b/src/legacy/core_plugins/console/public/src/autocomplete/components/template_autocomplete_component.js @@ -26,4 +26,4 @@ export class TemplateAutocompleteComponent extends ListComponent { getContextKey() { return 'template'; } -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/console/public/src/autocomplete/components/username_autocomplete_component.js b/src/legacy/core_plugins/console/public/src/autocomplete/components/username_autocomplete_component.js index fa973b87f1190..da3c63b69c610 100644 --- a/src/legacy/core_plugins/console/public/src/autocomplete/components/username_autocomplete_component.js +++ b/src/legacy/core_plugins/console/public/src/autocomplete/components/username_autocomplete_component.js @@ -40,4 +40,4 @@ export class UsernameAutocompleteComponent extends ListComponent { getContextKey() { return 'username'; } -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/console/public/src/sense_editor/mode/script_highlight_rules.js b/src/legacy/core_plugins/console/public/src/sense_editor/mode/script_highlight_rules.js index 93f5d48c0fa62..997a23d144acc 100644 --- a/src/legacy/core_plugins/console/public/src/sense_editor/mode/script_highlight_rules.js +++ b/src/legacy/core_plugins/console/public/src/sense_editor/mode/script_highlight_rules.js @@ -82,4 +82,4 @@ export function ScriptHighlightRules() { }; } -oop.inherits(ScriptHighlightRules, TextHighlightRules); \ No newline at end of file +oop.inherits(ScriptHighlightRules, TextHighlightRules); diff --git a/src/legacy/core_plugins/console/public/src/sense_editor/mode/worker/index.js b/src/legacy/core_plugins/console/public/src/sense_editor/mode/worker/index.js index c31708aaec636..010d32fb0c863 100644 --- a/src/legacy/core_plugins/console/public/src/sense_editor/mode/worker/index.js +++ b/src/legacy/core_plugins/console/public/src/sense_editor/mode/worker/index.js @@ -20,4 +20,4 @@ export const workerModule = { id: 'sense_editor/mode/worker', src: require('!!raw-loader!./worker.js') -}; \ No newline at end of file +}; diff --git a/src/legacy/core_plugins/console/server/__tests__/elasticsearch_proxy_config.js b/src/legacy/core_plugins/console/server/__tests__/elasticsearch_proxy_config.js index 6a5264e6e4358..f512949f41086 100644 --- a/src/legacy/core_plugins/console/server/__tests__/elasticsearch_proxy_config.js +++ b/src/legacy/core_plugins/console/server/__tests__/elasticsearch_proxy_config.js @@ -18,77 +18,77 @@ */ import expect from 'expect.js'; +import moment from 'moment'; import fs from 'fs'; import { promisify } from 'bluebird'; import { getElasticsearchProxyConfig } from '../elasticsearch_proxy_config'; import https from 'https'; import http from 'http'; -import sinon from 'sinon'; const readFileAsync = promisify(fs.readFile, fs); +const getDefaultElasticsearchConfig = () => { + return { + hosts: ['http://localhost:9200', 'http://192.168.1.1:1234'], + requestTimeout: moment.duration(30000), + ssl: { certificateAuthorities: [], verificationMode: 'full' }, + }; +}; + describe('plugins/console', function () { describe('#getElasticsearchProxyConfig', function () { - - let server; - - beforeEach(function () { - const stub = sinon.stub(); - server = { - config() { - return { - get: stub - }; - } - }; - - server.config().get.withArgs('elasticsearch.hosts').returns(['http://localhost:9200']); - server.config().get.withArgs('elasticsearch.ssl.verificationMode').returns('full'); - }); - - const setElasticsearchConfig = (key, value) => { - server.config().get.withArgs(`elasticsearch.${key}`).returns(value); - }; - it('sets timeout', function () { const value = 1000; - setElasticsearchConfig('requestTimeout', value); - const proxyConfig = getElasticsearchProxyConfig(server); + const proxyConfig = getElasticsearchProxyConfig({ + ...getDefaultElasticsearchConfig(), + requestTimeout: moment.duration(value), + }); expect(proxyConfig.timeout).to.be(value); }); it(`uses https.Agent when url's protocol is https`, function () { - setElasticsearchConfig('hosts', ['https://localhost:9200']); - const { agent } = getElasticsearchProxyConfig(server); + const { agent } = getElasticsearchProxyConfig({ + ...getDefaultElasticsearchConfig(), + hosts: ['https://localhost:9200'], + }); expect(agent).to.be.a(https.Agent); }); it(`uses http.Agent when url's protocol is http`, function () { - setElasticsearchConfig('hosts', ['http://localhost:9200']); - const { agent } = getElasticsearchProxyConfig(server); + const { agent } = getElasticsearchProxyConfig(getDefaultElasticsearchConfig()); expect(agent).to.be.a(http.Agent); }); describe('ssl', function () { + let config; beforeEach(function () { - setElasticsearchConfig('hosts', ['https://localhost:9200']); + config = { + ...getDefaultElasticsearchConfig(), + hosts: ['https://localhost:9200'], + }; }); it('sets rejectUnauthorized to false when verificationMode is none', function () { - setElasticsearchConfig('ssl.verificationMode', 'none'); - const { agent } = getElasticsearchProxyConfig(server); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { ...config.ssl, verificationMode: 'none' } + }); expect(agent.options.rejectUnauthorized).to.be(false); }); it('sets rejectUnauthorized to true when verificationMode is certificate', function () { - setElasticsearchConfig('ssl.verificationMode', 'certificate'); - const { agent } = getElasticsearchProxyConfig(server); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { ...config.ssl, verificationMode: 'certificate' } + }); expect(agent.options.rejectUnauthorized).to.be(true); }); it('sets checkServerIdentity to not check hostname when verificationMode is certificate', function () { - setElasticsearchConfig('ssl.verificationMode', 'certificate'); - const { agent } = getElasticsearchProxyConfig(server); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { ...config.ssl, verificationMode: 'certificate' } + }); const cert = { subject: { @@ -102,44 +102,60 @@ describe('plugins/console', function () { }); it('sets rejectUnauthorized to true when verificationMode is full', function () { - setElasticsearchConfig('ssl.verificationMode', 'full'); - const { agent } = getElasticsearchProxyConfig(server); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { ...config.ssl, verificationMode: 'full' } + }); expect(agent.options.rejectUnauthorized).to.be(true); }); it(`doesn't set checkServerIdentity when verificationMode is full`, function () { - setElasticsearchConfig('ssl.verificationMode', 'full'); - const { agent } = getElasticsearchProxyConfig(server); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { ...config.ssl, verificationMode: 'full' } + }); expect(agent.options.checkServerIdentity).to.be(undefined); }); it(`sets ca when certificateAuthorities are specified`, function () { - setElasticsearchConfig('ssl.certificateAuthorities', [__dirname + '/fixtures/ca.crt']); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { ...config.ssl, certificateAuthorities: [__dirname + '/fixtures/ca.crt'] } + }); - const { agent } = getElasticsearchProxyConfig(server); expect(agent.options.ca).to.contain('test ca certificate\n'); }); describe('when alwaysPresentCertificate is false', () => { it(`doesn't set cert and key when certificate and key paths are specified`, function () { - setElasticsearchConfig('ssl.alwaysPresentCertificate', false); - setElasticsearchConfig('ssl.certificate', __dirname + '/fixtures/cert.crt'); - setElasticsearchConfig('ssl.key', __dirname + '/fixtures/cert.key'); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { + ...config.ssl, + alwaysPresentCertificate: false, + certificate: __dirname + '/fixtures/cert.crt', + key: __dirname + '/fixtures/cert.key', + } + }); - const { agent } = getElasticsearchProxyConfig(server); expect(agent.options.cert).to.be(undefined); expect(agent.options.key).to.be(undefined); }); it(`doesn't set passphrase when certificate, key and keyPassphrase are specified`, function () { - setElasticsearchConfig('ssl.alwaysPresentCertificate', false); - setElasticsearchConfig('ssl.certificate', __dirname + '/fixtures/cert.crt'); - setElasticsearchConfig('ssl.key', __dirname + '/fixtures/cert.key'); - setElasticsearchConfig('ssl.keyPassphrase', 'secret'); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { + ...config.ssl, + alwaysPresentCertificate: false, + certificate: __dirname + '/fixtures/cert.crt', + key: __dirname + '/fixtures/cert.key', + keyPassphrase: 'secret', + } + }); - const { agent } = getElasticsearchProxyConfig(server); expect(agent.options.passphrase).to.be(undefined); }); }); @@ -148,43 +164,64 @@ describe('plugins/console', function () { it(`sets cert and key when certificate and key paths are specified`, async function () { const certificatePath = __dirname + '/fixtures/cert.crt'; const keyPath = __dirname + '/fixtures/cert.key'; - setElasticsearchConfig('ssl.alwaysPresentCertificate', true); - setElasticsearchConfig('ssl.certificate', certificatePath); - setElasticsearchConfig('ssl.key', keyPath); - const { agent } = getElasticsearchProxyConfig(server); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { + ...config.ssl, + alwaysPresentCertificate: true, + certificate: certificatePath, + key: keyPath, + } + }); + expect(agent.options.cert).to.be(await readFileAsync(certificatePath, 'utf8')); expect(agent.options.key).to.be(await readFileAsync(keyPath, 'utf8')); }); it(`sets passphrase when certificate, key and keyPassphrase are specified`, function () { - setElasticsearchConfig('ssl.alwaysPresentCertificate', true); - setElasticsearchConfig('ssl.certificate', __dirname + '/fixtures/cert.crt'); - setElasticsearchConfig('ssl.key', __dirname + '/fixtures/cert.key'); - setElasticsearchConfig('ssl.keyPassphrase', 'secret'); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { + ...config.ssl, + alwaysPresentCertificate: true, + certificate: __dirname + '/fixtures/cert.crt', + key: __dirname + '/fixtures/cert.key', + keyPassphrase: 'secret', + } + }); - const { agent } = getElasticsearchProxyConfig(server); expect(agent.options.passphrase).to.be('secret'); }); it(`doesn't set cert when only certificate path is specified`, async function () { const certificatePath = __dirname + '/fixtures/cert.crt'; - setElasticsearchConfig('ssl.alwaysPresentCertificate', true); - setElasticsearchConfig('ssl.certificate', certificatePath); - setElasticsearchConfig('ssl.key', undefined); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { + ...config.ssl, + alwaysPresentCertificate: true, + certificate: certificatePath, + key: undefined, + } + }); - const { agent } = getElasticsearchProxyConfig(server); expect(agent.options.cert).to.be(undefined); expect(agent.options.key).to.be(undefined); }); it(`doesn't set key when only key path is specified`, async function () { const keyPath = __dirname + '/fixtures/cert.key'; - setElasticsearchConfig('ssl.alwaysPresentCertificate', true); - setElasticsearchConfig('ssl.certificate', undefined); - setElasticsearchConfig('ssl.key', keyPath); + const { agent } = getElasticsearchProxyConfig({ + ...config, + ssl: { + ...config.ssl, + alwaysPresentCertificate: true, + certificate: undefined, + key: keyPath, + } + }); - const { agent } = getElasticsearchProxyConfig(server); expect(agent.options.cert).to.be(undefined); expect(agent.options.key).to.be(undefined); }); diff --git a/src/legacy/core_plugins/console/server/__tests__/set_headers.js b/src/legacy/core_plugins/console/server/__tests__/set_headers.js new file mode 100644 index 0000000000000..0bbfe8d443cf9 --- /dev/null +++ b/src/legacy/core_plugins/console/server/__tests__/set_headers.js @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 expect from 'expect.js'; +import { setHeaders } from '../set_headers'; + +describe('#set_headers', function () { + it('throws if not given an object as the first argument', function () { + const fn = () => setHeaders(null, {}); + expect(fn).to.throwError(); + }); + + it('throws if not given an object as the second argument', function () { + const fn = () => setHeaders({}, null); + expect(fn).to.throwError(); + }); + + it('returns a new object', function () { + const originalHeaders = {}; + const newHeaders = {}; + const returnedHeaders = setHeaders(originalHeaders, newHeaders); + expect(returnedHeaders).not.to.be(originalHeaders); + expect(returnedHeaders).not.to.be(newHeaders); + }); + + it('returns object with newHeaders merged with originalHeaders', function () { + const originalHeaders = { foo: 'bar' }; + const newHeaders = { one: 'two' }; + const returnedHeaders = setHeaders(originalHeaders, newHeaders); + expect(returnedHeaders).to.eql({ foo: 'bar', one: 'two' }); + }); + + it('returns object where newHeaders takes precedence for any matching keys', function () { + const originalHeaders = { foo: 'bar' }; + const newHeaders = { one: 'two', foo: 'notbar' }; + const returnedHeaders = setHeaders(originalHeaders, newHeaders); + expect(returnedHeaders).to.eql({ foo: 'notbar', one: 'two' }); + }); +}); diff --git a/src/legacy/core_plugins/console/server/elasticsearch_proxy_config.js b/src/legacy/core_plugins/console/server/elasticsearch_proxy_config.js index e7e63e55719d3..d42a85ce25a96 100644 --- a/src/legacy/core_plugins/console/server/elasticsearch_proxy_config.js +++ b/src/legacy/core_plugins/console/server/elasticsearch_proxy_config.js @@ -25,16 +25,13 @@ import url from 'url'; const readFile = (file) => readFileSync(file, 'utf8'); -const createAgent = (server) => { - const config = server.config(); - const target = url.parse( - _.head(config.get('elasticsearch.hosts')) - ); +const createAgent = (legacyConfig) => { + const target = url.parse(_.head(legacyConfig.hosts)); if (!/^https/.test(target.protocol)) return new http.Agent(); const agentOptions = {}; - const verificationMode = config.get('elasticsearch.ssl.verificationMode'); + const verificationMode = legacyConfig.ssl && legacyConfig.ssl.verificationMode; switch (verificationMode) { case 'none': agentOptions.rejectUnauthorized = false; @@ -52,26 +49,27 @@ const createAgent = (server) => { throw new Error(`Unknown ssl verificationMode: ${verificationMode}`); } - if (_.size(config.get('elasticsearch.ssl.certificateAuthorities'))) { - agentOptions.ca = config.get('elasticsearch.ssl.certificateAuthorities').map(readFile); + if (legacyConfig.ssl && legacyConfig.ssl.certificateAuthorities.length > 0) { + agentOptions.ca = legacyConfig.ssl.certificateAuthorities.map(readFile); } if ( - config.get('elasticsearch.ssl.alwaysPresentCertificate') && - config.get('elasticsearch.ssl.certificate') && - config.get('elasticsearch.ssl.key') + legacyConfig.ssl && + legacyConfig.ssl.alwaysPresentCertificate && + legacyConfig.ssl.certificate && + legacyConfig.ssl.key ) { - agentOptions.cert = readFile(config.get('elasticsearch.ssl.certificate')); - agentOptions.key = readFile(config.get('elasticsearch.ssl.key')); - agentOptions.passphrase = config.get('elasticsearch.ssl.keyPassphrase'); + agentOptions.cert = readFile(legacyConfig.ssl.certificate); + agentOptions.key = readFile(legacyConfig.ssl.key); + agentOptions.passphrase = legacyConfig.ssl.keyPassphrase; } return new https.Agent(agentOptions); }; -export const getElasticsearchProxyConfig = (server) => { +export const getElasticsearchProxyConfig = (legacyConfig) => { return { - timeout: server.config().get('elasticsearch.requestTimeout'), - agent: createAgent(server) + timeout: legacyConfig.requestTimeout.asMilliseconds(), + agent: createAgent(legacyConfig) }; }; diff --git a/src/legacy/core_plugins/elasticsearch/lib/set_headers.js b/src/legacy/core_plugins/console/server/set_headers.js similarity index 94% rename from src/legacy/core_plugins/elasticsearch/lib/set_headers.js rename to src/legacy/core_plugins/console/server/set_headers.js index f50fa31b1dffc..4b46e864e118f 100644 --- a/src/legacy/core_plugins/elasticsearch/lib/set_headers.js +++ b/src/legacy/core_plugins/console/server/set_headers.js @@ -19,7 +19,7 @@ import { isPlainObject } from 'lodash'; -export default function setHeaders(originalHeaders, newHeaders) { +export function setHeaders(originalHeaders, newHeaders) { if (!isPlainObject(originalHeaders)) { throw new Error(`Expected originalHeaders to be an object, but ${typeof originalHeaders} given`); } diff --git a/src/legacy/core_plugins/elasticsearch/index.d.ts b/src/legacy/core_plugins/elasticsearch/index.d.ts index 7ab4700d379d2..9577f92545384 100644 --- a/src/legacy/core_plugins/elasticsearch/index.d.ts +++ b/src/legacy/core_plugins/elasticsearch/index.d.ts @@ -165,15 +165,6 @@ interface RequestHeaders { [name: string]: string; } -interface ElasticsearchClientLogging { - error(err: Error): void; - warning(message: string): void; - trace(method: string, options: { path: string }, query?: string, statusCode?: number): void; - info(): void; - debug(): void; - close(): void; -} - interface AssistantAPIClientParams extends GenericParams { path: '/_migration/assistance'; method: 'GET'; @@ -531,9 +522,7 @@ export interface CallCluster { } export interface ElasticsearchPlugin { - ElasticsearchClientLogging: ElasticsearchClientLogging; getCluster(name: string): Cluster; createCluster(name: string, config: ClusterConfig): Cluster; - filterHeaders(originalHeaders: RequestHeaders, headersToKeep: string[]): void; waitUntilReady(): Promise; } diff --git a/src/legacy/core_plugins/elasticsearch/index.js b/src/legacy/core_plugins/elasticsearch/index.js index 53781932adf3e..7eeea23b5473c 100644 --- a/src/legacy/core_plugins/elasticsearch/index.js +++ b/src/legacy/core_plugins/elasticsearch/index.js @@ -17,80 +17,91 @@ * under the License. */ +import { combineLatest } from 'rxjs'; +import { first, map } from 'rxjs/operators'; import healthCheck from './lib/health_check'; -import { createDataCluster } from './lib/create_data_cluster'; -import { createAdminCluster } from './lib/create_admin_cluster'; -import { clientLogger } from './lib/client_logger'; -import { createClusters } from './lib/create_clusters'; +import { Cluster } from './lib/cluster'; import { createProxy } from './lib/create_proxy'; -import filterHeaders from './lib/filter_headers'; -import { DEFAULT_API_VERSION } from './lib/default_api_version'; - -const DEFAULT_REQUEST_HEADERS = ['authorization']; export default function (kibana) { + let defaultVars; + return new kibana.Plugin({ require: ['kibana'], - config(Joi) { - const sslSchema = Joi.object({ - verificationMode: Joi.string().valid('none', 'certificate', 'full').default('full'), - certificateAuthorities: Joi.array().single().items(Joi.string()), - certificate: Joi.string(), - key: Joi.string(), - keyPassphrase: Joi.string(), - alwaysPresentCertificate: Joi.boolean().default(false), - }).default(); - - return Joi.object({ - enabled: Joi.boolean().default(true), - sniffOnStart: Joi.boolean().default(false), - sniffInterval: Joi.number().allow(false).default(false), - sniffOnConnectionFault: Joi.boolean().default(false), - hosts: Joi.array().items(Joi.string().uri({ scheme: ['http', 'https'] })).single().default('http://localhost:9200'), - preserveHost: Joi.boolean().default(true), - username: Joi.string(), - password: Joi.string(), - shardTimeout: Joi.number().default(30000), - requestTimeout: Joi.number().default(30000), - requestHeadersWhitelist: Joi.array().items().single().default(DEFAULT_REQUEST_HEADERS), - customHeaders: Joi.object().default({}), - pingTimeout: Joi.number().default(Joi.ref('requestTimeout')), - startupTimeout: Joi.number().default(5000), - logQueries: Joi.boolean().default(false), - ssl: sslSchema, - apiVersion: Joi.string().default(DEFAULT_API_VERSION), - healthCheck: Joi.object({ - delay: Joi.number().default(2500) - }).default(), - }).default(); - }, - - uiExports: { - injectDefaultVars(server, options) { - return { - esRequestTimeout: options.requestTimeout, - esShardTimeout: options.shardTimeout, - esApiVersion: options.apiVersion, - }; - } - }, - - init(server) { - const clusters = createClusters(server); - - server.expose('getCluster', clusters.get); - server.expose('createCluster', clusters.create); - - server.expose('filterHeaders', filterHeaders); - server.expose('ElasticsearchClientLogging', clientLogger(server)); - - createDataCluster(server); - createAdminCluster(server); + + uiExports: { injectDefaultVars: () => defaultVars }, + + async init(server) { + // All methods that ES plugin exposes are synchronous so we should get the first + // value from all observables here to be able to synchronously return and create + // cluster clients afterwards. + const [esConfig, adminCluster, dataCluster] = await combineLatest( + server.core.elasticsearch.legacy.config$, + server.core.elasticsearch.adminClient$, + server.core.elasticsearch.dataClient$ + ).pipe( + first(), + map(([config, adminClusterClient, dataClusterClient]) => [ + config, + new Cluster(adminClusterClient), + new Cluster(dataClusterClient) + ]) + ).toPromise(); + + defaultVars = { + esRequestTimeout: esConfig.requestTimeout.asMilliseconds(), + esShardTimeout: esConfig.shardTimeout.asMilliseconds(), + esApiVersion: esConfig.apiVersion, + }; + + const clusters = new Map(); + server.expose('getCluster', (name) => { + if (name === 'admin') { + return adminCluster; + } + + if (name === 'data') { + return dataCluster; + } + + return clusters.get(name); + }); + + server.expose('createCluster', (name, clientConfig = {}) => { + // NOTE: Not having `admin` and `data` clients provided by the core in `clusters` + // map implicitly allows to create custom `data` and `admin` clients. This is + // allowed intentionally to support custom `admin` cluster client created by the + // x-pack/monitoring bulk uploader. We should forbid that as soon as monitoring + // bulk uploader is refactored, see https://github.com/elastic/kibana/issues/31934. + if (clusters.has(name)) { + throw new Error(`cluster '${name}' already exists`); + } + + // We fill all the missing properties in the `clientConfig` using the default + // Elasticsearch config so that we don't depend on default values set and + // controlled by underlying Elasticsearch JS client. + const cluster = new Cluster(server.core.elasticsearch.createClient(name, { + ...esConfig, + ...clientConfig, + })); + + clusters.set(name, cluster); + + return cluster; + }); + + server.events.on('stop', () => { + for (const cluster of clusters.values()) { + cluster.close(); + } + + clusters.clear(); + }); createProxy(server); // Set up the health check service and start it. - const { start, waitUntilReady } = healthCheck(this, server); + const { start, waitUntilReady } = healthCheck(this, server, esConfig.healthCheckDelay.asMilliseconds()); server.expose('waitUntilReady', waitUntilReady); start(); } diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/cluster.js b/src/legacy/core_plugins/elasticsearch/lib/__tests__/cluster.js deleted file mode 100644 index e0156fbe066c7..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/cluster.js +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 expect from 'expect.js'; -import { Cluster } from '../cluster'; -import sinon from 'sinon'; -import { errors as esErrors } from 'elasticsearch'; -import { set, partial } from 'lodash'; - -describe('plugins/elasticsearch', function () { - describe('cluster', function () { - let cluster; - const config = { - url: 'http://localhost:9200', - ssl: { verificationMode: 'full' }, - requestHeadersWhitelist: [ 'authorization' ] - }; - - beforeEach(() => { - cluster = new Cluster(config); - }); - - it('persists the config', () => { - expect(cluster._config).to.eql(config); - }); - - it('exposes error definitions', () => { - expect(cluster.errors).to.be(esErrors); - }); - - it('closes the clients', () => { - cluster._client.close = sinon.spy(); - cluster._noAuthClient.close = sinon.spy(); - cluster.close(); - - sinon.assert.calledOnce(cluster._client.close); - sinon.assert.calledOnce(cluster._noAuthClient.close); - }); - - it('closes clients created with createClient', () => { - const client = cluster.createClient(); - sinon.stub(client, 'close'); - cluster.close(); - sinon.assert.calledOnce(client.close); - }); - - it('protects the config from changes', () => { - const localRequestHeadersWhitelist = cluster.getRequestHeadersWhitelist(); - expect(localRequestHeadersWhitelist.length).to.not.equal(config.requestHeadersWhitelist); - }); - - describe('callWithInternalUser', () => { - let client; - - beforeEach(() => { - client = cluster._client = sinon.stub(); - set(client, 'nodes.info', sinon.stub().returns(Promise.resolve())); - }); - - it('should return a function', () => { - expect(cluster.callWithInternalUser).to.be.a('function'); - }); - - it('throws an error for an invalid endpoint', () => { - const fn = partial(cluster.callWithInternalUser, 'foo'); - expect(fn).to.throwException(/called with an invalid endpoint: foo/); - }); - - it('calls the client with params', () => { - const params = { foo: 'Foo' }; - cluster.callWithInternalUser('nodes.info', params); - - sinon.assert.calledOnce(client.nodes.info); - expect(client.nodes.info.getCall(0).args[0]).to.eql(params); - }); - }); - - describe('callWithRequest', () => { - let client; - - beforeEach(() => { - client = cluster._noAuthClient = sinon.stub(); - set(client, 'nodes.info', sinon.stub().returns(Promise.resolve())); - }); - - it('should return a function', () => { - expect(cluster.callWithRequest).to.be.a('function'); - }); - - it('throws an error for an invalid endpoint', () => { - const fn = partial(cluster.callWithRequest, {}, 'foo'); - expect(fn).to.throwException(/called with an invalid endpoint: foo/); - }); - - it('calls the client with params', () => { - const params = { foo: 'Foo' }; - cluster.callWithRequest({}, 'nodes.info', params); - - sinon.assert.calledOnce(client.nodes.info); - expect(client.nodes.info.getCall(0).args[0]).to.eql(params); - }); - - it('passes only whitelisted headers', () => { - const headers = { authorization: 'Basic TEST' }; - const request = { - headers: { - ...headers, - foo: 'Foo' - } - }; - - cluster.callWithRequest(request, 'nodes.info'); - - sinon.assert.calledOnce(client.nodes.info); - expect(client.nodes.info.getCall(0).args[0]).to.eql({ - headers: headers - }); - }); - - describe('wrap401Errors', () => { - let handler; - let error; - - beforeEach(() => { - error = new Error('Authentication required'); - error.statusCode = 401; - - handler = sinon.stub(); - }); - - it('ensures WWW-Authenticate header', async () => { - set(client, 'mock.401', sinon.stub().returns(Promise.reject(error))); - await cluster.callWithRequest({}, 'mock.401', {}, { wrap401Errors: true }).catch(handler); - - sinon.assert.calledOnce(handler); - expect(handler.getCall(0).args[0].output.headers['WWW-Authenticate']).to.eql('Basic realm="Authorization Required"'); - }); - - it('persists WWW-Authenticate header', async () => { - set(error, 'body.error.header[WWW-Authenticate]', 'Basic realm="Test"'); - set(client, 'mock.401', sinon.stub().returns(Promise.reject(error))); - await cluster.callWithRequest({}, 'mock.401', {}, { wrap401Errors: true }).catch(handler); - - sinon.assert.calledOnce(handler); - expect(handler.getCall(0).args[0].output.headers['WWW-Authenticate']).to.eql('Basic realm="Test"'); - }); - }); - }); - }); -}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js b/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js deleted file mode 100644 index 71d457a5b7973..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_admin_cluster.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 expect from 'expect.js'; -import sinon from 'sinon'; -import { set, get, partial } from 'lodash'; -import { createAdminCluster } from '../create_admin_cluster'; - -describe('plugins/elasticsearch', function () { - describe('create_admin_cluster', function () { - let cluster; - let server; - - beforeEach(() => { - const config = { - elasticsearch: { - url: 'http://localhost:9200', - logQueries: true - } - }; - - server = sinon.spy(); - - cluster = { - close: sinon.spy() - }; - - set(server, 'plugins.elasticsearch.createCluster', sinon.mock().returns(cluster)); - set(server, 'on', sinon.spy()); - - server.config = () => { - return { get: partial(get, config) }; - }; - - createAdminCluster(server); - }); - - it('creates the cluster', () => { - const { createCluster } = server.plugins.elasticsearch; - - sinon.assert.calledOnce(createCluster); - expect(createCluster.getCall(0).args[0]).to.eql('admin'); - expect(createCluster.getCall(0).args[1].url).to.eql('http://localhost:9200'); - }); - - it('sets client logger for cluster options', () => { - const { createCluster } = server.plugins.elasticsearch; - const firstCall = createCluster.getCall(0); - const Log = firstCall.args[1].log; - const logger = new Log; - - sinon.assert.calledOnce(createCluster); - expect(firstCall.args[0]).to.eql('admin'); - expect(firstCall.args[1].url).to.eql('http://localhost:9200'); - expect(logger.tags).to.eql(['admin']); - expect(logger.logQueries).to.eql(true); - }); - }); -}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_agent.js b/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_agent.js deleted file mode 100644 index 9f9d50d843348..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_agent.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 expect from 'expect.js'; -import createAgent from '../create_agent'; -import https from 'https'; -import http from 'http'; - -describe('plugins/elasticsearch', function () { - describe('lib/create_agent', function () { - - it(`uses http.Agent when url's protocol is http`, function () { - const config = { - url: 'http://localhost:9200' - }; - - const agent = createAgent(config); - expect(agent).to.be.a(http.Agent); - }); - - it(`throws an Error when url's protocol is https and ssl.verificationMode isn't set`, function () { - const config = { - url: 'https://localhost:9200' - }; - - expect(createAgent).withArgs(config).to.throwException(); - }); - - it(`uses https.Agent when url's protocol is https and ssl.verificationMode is full`, function () { - const config = { - url: 'https://localhost:9200', - ssl: { - verificationMode: 'full' - } - }; - - const agent = createAgent(config); - expect(agent).to.be.a(https.Agent); - }); - }); -}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_clusters.js b/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_clusters.js deleted file mode 100644 index c10e8e6ebae0e..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_clusters.js +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 expect from 'expect.js'; -import { createClusters } from '../create_clusters'; -import sinon from 'sinon'; -import { partial } from 'lodash'; -import Hapi from 'hapi'; - -import * as ClusterNS from '../cluster'; - -describe('plugins/elasticsearch', function () { - describe('createClusters', function () { - let clusters; - let server; - - beforeEach(() => { - server = { - plugins: { - elasticsearch: {} - }, - expose: sinon.mock(), - events: { - on: sinon.stub(), - } - }; - - clusters = createClusters(server); - }); - - describe('createCluster', () => { - let cluster; - const config = { - url: 'http://localhost:9200', - ssl: { - verificationMode: 'none' - } - }; - - beforeEach(() => { - cluster = clusters.create('admin', config); - }); - - it('returns a cluster', () => { - expect(cluster).to.be.a(ClusterNS.Cluster); - }); - - it('persists the cluster', () => { - expect(clusters.get('admin')).to.be.a(ClusterNS.Cluster); - }); - - it('throws if cluster already exists', () => { - const fn = partial(clusters.create, 'admin', config); - expect(fn).to.throwException(/cluster \'admin\' already exists/); - }); - }); - }); - - describe('server stop', () => { - const sandbox = sinon.createSandbox(); - - beforeEach(() => { - sandbox.stub(ClusterNS, 'Cluster').callsFake(function () { - this.stub = true; - this.close = sinon.stub(); - }); - }); - - after(() => { - sandbox.restore(); - }); - - it('closes all clusters', async () => { - const server = new Hapi.Server(); - const clusters = createClusters(server); - const cluster = clusters.create('name', { config: true }); - expect(cluster).to.have.property('stub', true); - sinon.assert.notCalled(cluster.close); - await server.start(); - sinon.assert.notCalled(cluster.close); - await server.stop(); - sinon.assert.calledOnce(cluster.close); - }); - }); -}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js b/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js deleted file mode 100644 index 10a2e0dab5ab7..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/create_data_cluster.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 expect from 'expect.js'; -import sinon from 'sinon'; -import { set, get, partial } from 'lodash'; -import { createDataCluster } from '../create_data_cluster'; - -describe('plugins/elasticsearch', function () { - describe('create_data_cluster', function () { - let cluster; - let server; - let config; - - beforeEach(() => { - config = { - elasticsearch: { - url: 'http://localhost:9200', - logQueries: true - } - }; - - server = sinon.spy(); - - cluster = { - close: sinon.spy() - }; - - set(server, 'plugins.elasticsearch.createCluster', sinon.mock().returns(cluster)); - set(server, 'on', sinon.spy()); - - server.config = () => { - return { get: partial(get, config) }; - }; - }); - - it('creates the cluster with elasticsearch config', () => { - createDataCluster(server); - - const { createCluster } = server.plugins.elasticsearch; - - sinon.assert.calledOnce(createCluster); - expect(createCluster.getCall(0).args[0]).to.eql('data'); - expect(createCluster.getCall(0).args[1].url).to.eql('http://localhost:9200'); - }); - - it('sets client logger for cluster options', () => { - createDataCluster(server); - - const { createCluster } = server.plugins.elasticsearch; - const firstCall = createCluster.getCall(0); - const Log = firstCall.args[1].log; - const logger = new Log; - - sinon.assert.calledOnce(createCluster); - expect(firstCall.args[0]).to.eql('data'); - expect(firstCall.args[1].url).to.eql('http://localhost:9200'); - expect(logger.tags).to.eql(['data']); - expect(logger.logQueries).to.eql(true); - }); - }); -}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/ca.crt b/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/ca.crt deleted file mode 100644 index 075fdd038daff..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/ca.crt +++ /dev/null @@ -1 +0,0 @@ -test ca certificate diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.crt b/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.crt deleted file mode 100644 index 360cdfaaaa5a9..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.crt +++ /dev/null @@ -1 +0,0 @@ -test certificate diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.key b/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.key deleted file mode 100644 index 04d3bfef24188..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.key +++ /dev/null @@ -1 +0,0 @@ -test key diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/health_check.js b/src/legacy/core_plugins/elasticsearch/lib/__tests__/health_check.js index d4a15821cb509..0c588b98e9a70 100644 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/health_check.js +++ b/src/legacy/core_plugins/elasticsearch/lib/__tests__/health_check.js @@ -27,7 +27,6 @@ import healthCheck from '../health_check'; import kibanaVersion from '../kibana_version'; const esPort = 9220; -const esUrl = `http://elastic:changement@localhost:9220`; describe('plugins/elasticsearch', () => { describe('lib/health_check', function () { @@ -58,7 +57,7 @@ describe('plugins/elasticsearch', () => { } }; - cluster = { callWithInternalUser: sinon.stub() }; + cluster = { callWithInternalUser: sinon.stub(), errors: { NoConnections } }; cluster.callWithInternalUser.withArgs('index', sinon.match.any).returns(Promise.resolve()); cluster.callWithInternalUser.withArgs('mget', sinon.match.any).returns(Promise.resolve({ ok: true })); cluster.callWithInternalUser.withArgs('get', sinon.match.any).returns(Promise.resolve({ found: false })); @@ -73,19 +72,11 @@ describe('plugins/elasticsearch', () => { } })); - // setup the config().get()/.set() stubs - const get = sinon.stub(); - get.withArgs('elasticsearch.hosts').returns([esUrl]); - get.withArgs('kibana.index').returns('.my-kibana'); - get.withArgs('pkg.version').returns('1.0.0'); - - const set = sinon.stub(); - // Setup the server mock server = { logWithMetadata: sinon.stub(), info: { port: 5601 }, - config: function () { return { get, set }; }, + config: () => ({ get: sinon.stub() }), plugins: { elasticsearch: { getCluster: sinon.stub().returns(cluster) @@ -94,7 +85,7 @@ describe('plugins/elasticsearch', () => { ext: sinon.stub() }; - health = healthCheck(plugin, server); + health = healthCheck(plugin, server, 0); }); afterEach(() => sandbox.restore()); diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/parse_config.js b/src/legacy/core_plugins/elasticsearch/lib/__tests__/parse_config.js deleted file mode 100644 index f9b16d760bdbf..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/parse_config.js +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 expect from 'expect.js'; -import { parseConfig } from '../parse_config'; - -describe('plugins/elasticsearch', function () { - describe('lib/parse_config', function () { - describe('ssl', function () { - let serverConfig; - - beforeEach(function () { - serverConfig = { - hosts: ['https://localhost:9200'], - ssl: { - verificationMode: 'full' - } - }; - }); - - it('throws an Exception when verificationMode is undefined', function () { - delete serverConfig.ssl.verificationMode; - - expect(parseConfig).withArgs(serverConfig).to.throwException(); - }); - - it('sets rejectUnauthorized to false when verificationMode is none', function () { - serverConfig.ssl.verificationMode = 'none'; - const config = parseConfig(serverConfig); - expect(config.ssl.rejectUnauthorized).to.be(false); - }); - - it('sets rejectUnauthorized to true when verificationMode is certificate', function () { - serverConfig.ssl.verificationMode = 'certificate'; - const config = parseConfig(serverConfig); - expect(config.ssl.rejectUnauthorized).to.be(true); - }); - - it('sets checkServerIdentity to not check hostname when verificationMode is certificate', function () { - serverConfig.ssl.verificationMode = 'certificate'; - const config = parseConfig(serverConfig); - - const cert = { - subject: { - CN: 'wrong.com' - } - }; - - expect(config.ssl.checkServerIdentity).withArgs('right.com', cert).to.not.throwException(); - const result = config.ssl.checkServerIdentity('right.com', cert); - expect(result).to.be(undefined); - }); - - it('sets rejectUnauthorized to true when verificationMode is full', function () { - serverConfig.ssl.verificationMode = 'full'; - const config = parseConfig(serverConfig); - - expect(config.ssl.rejectUnauthorized).to.be(true); - }); - - it(`doesn't set checkServerIdentity when verificationMode is full`, function () { - serverConfig.ssl.verificationMode = 'full'; - const config = parseConfig(serverConfig); - - expect(config.ssl.checkServerIdentity).to.be(undefined); - }); - - it(`sets ca when certificateAuthorities are specified`, function () { - serverConfig.ssl.certificateAuthorities = [__dirname + '/fixtures/ca.crt']; - - const config = parseConfig(serverConfig); - expect(config.ssl.ca).to.contain('test ca certificate\n'); - }); - - it(`by default sets cert and key when certificate and key paths are specified`, function () { - serverConfig.ssl.certificate = __dirname + '/fixtures/cert.crt'; - serverConfig.ssl.key = __dirname + '/fixtures/cert.key'; - - const config = parseConfig(serverConfig); - expect(config.ssl.cert).to.be('test certificate\n'); - expect(config.ssl.key).to.be('test key\n'); - }); - - it(`by default sets passphrase when certificate, key and keyPassphrase are specified`, function () { - serverConfig.ssl.certificate = __dirname + '/fixtures/cert.crt'; - serverConfig.ssl.key = __dirname + '/fixtures/cert.key'; - serverConfig.ssl.keyPassphrase = 'secret'; - - const config = parseConfig(serverConfig); - expect(config.ssl.passphrase).to.be('secret'); - }); - - it(`doesn't set cert and key when ignoreCertAndKey is true`, function () { - serverConfig.ssl.certificate = __dirname + '/fixtures/cert.crt'; - serverConfig.ssl.key = __dirname + '/fixtures/cert.key'; - - const config = parseConfig(serverConfig, { ignoreCertAndKey: true }); - expect(config.ssl.cert).to.be(undefined); - expect(config.ssl.key).to.be(undefined); - }); - - it(`by default sets passphrase when ignoreCertAndKey is true`, function () { - serverConfig.ssl.certificate = __dirname + '/fixtures/cert.crt'; - serverConfig.ssl.key = __dirname + '/fixtures/cert.key'; - serverConfig.ssl.keyPassphrase = 'secret'; - - const config = parseConfig(serverConfig, { ignoreCertAndKey: true }); - expect(config.ssl.passphrase).to.be(undefined); - }); - - describe('port', () => { - it('uses the specified port', () => { - const config1 = parseConfig(serverConfig).hosts[0]; - expect(config1.port).to.be('9200'); - - serverConfig.hosts = ['https://localhost:555']; - const config2 = parseConfig(serverConfig).hosts[0]; - expect(config2.port).to.be('555'); - }); - - it('uses port 80 if http and no specified port', () => { - serverConfig.hosts = ['http://localhost']; - const config2 = parseConfig(serverConfig).hosts[0]; - expect(config2.port).to.be('80'); - }); - - it ('uses port 443 if https and no specified port', () => { - serverConfig.hosts = ['https://localhost']; - const config2 = parseConfig(serverConfig).hosts[0]; - expect(config2.port).to.be('443'); - }); - }); - }); - }); -}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/__tests__/set_headers.js b/src/legacy/core_plugins/elasticsearch/lib/__tests__/set_headers.js deleted file mode 100644 index 861e3b751a381..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/__tests__/set_headers.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 expect from 'expect.js'; -import setHeaders from '../set_headers'; - -describe('plugins/elasticsearch', function () { - describe('lib/set_headers', function () { - it('throws if not given an object as the first argument', function () { - const fn = () => setHeaders(null, {}); - expect(fn).to.throwError(); - }); - - it('throws if not given an object as the second argument', function () { - const fn = () => setHeaders({}, null); - expect(fn).to.throwError(); - }); - - it('returns a new object', function () { - const originalHeaders = {}; - const newHeaders = {}; - const returnedHeaders = setHeaders(originalHeaders, newHeaders); - expect(returnedHeaders).not.to.be(originalHeaders); - expect(returnedHeaders).not.to.be(newHeaders); - }); - - it('returns object with newHeaders merged with originalHeaders', function () { - const originalHeaders = { foo: 'bar' }; - const newHeaders = { one: 'two' }; - const returnedHeaders = setHeaders(originalHeaders, newHeaders); - expect(returnedHeaders).to.eql({ foo: 'bar', one: 'two' }); - }); - - it('returns object where newHeaders takes precedence for any matching keys', function () { - const originalHeaders = { foo: 'bar' }; - const newHeaders = { one: 'two', foo: 'notbar' }; - const returnedHeaders = setHeaders(originalHeaders, newHeaders); - expect(returnedHeaders).to.eql({ foo: 'notbar', one: 'two' }); - }); - }); -}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/client_logger.js b/src/legacy/core_plugins/elasticsearch/lib/client_logger.js deleted file mode 100644 index 90079ddf91889..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/client_logger.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 function clientLogger(server) { - return class ElasticsearchClientLogging { - // additional tags to differentiate connection - tags = []; - - logQueries = false; - - error(err) { - server.log(['error', 'elasticsearch'].concat(this.tags), err); - } - - warning(message) { - server.log(['warning', 'elasticsearch'].concat(this.tags), message); - } - - trace(method, options, query, _response, statusCode) { - /* Check if query logging is enabled - * It requires Kibana to be configured with verbose logging turned on. */ - if (this.logQueries) { - const methodAndPath = `${method} ${options.path}`; - const queryDsl = query ? query.trim() : ''; - server.log(['elasticsearch', 'query', 'debug'].concat(this.tags), [ - statusCode, - methodAndPath, - queryDsl - ].join('\n')); - } - } - - - // elasticsearch-js expects the following functions to exist - - info() {} - - debug() {} - - close() {} - }; -} diff --git a/src/legacy/core_plugins/elasticsearch/lib/cluster.js b/src/legacy/core_plugins/elasticsearch/lib/cluster.js deleted file mode 100644 index 338e72d2cc31f..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/cluster.js +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 elasticsearch from 'elasticsearch'; -import { get, set, isEmpty, cloneDeep, pick } from 'lodash'; -import toPath from 'lodash/internal/toPath'; -import Boom from 'boom'; - -import filterHeaders from './filter_headers'; -import { parseConfig } from './parse_config'; - -export class Cluster { - constructor(config) { - this._config = { - ...config - }; - this.errors = elasticsearch.errors; - - this._clients = new Set(); - this._client = this.createClient(); - this._noAuthClient = this.createClient( - { auth: false }, - { ignoreCertAndKey: !this.getSsl().alwaysPresentCertificate } - ); - - return this; - } - - callWithRequest = (req = {}, endpoint, clientParams = {}, options = {}) => { - if (req.headers) { - const filteredHeaders = filterHeaders(req.headers, this.getRequestHeadersWhitelist()); - set(clientParams, 'headers', filteredHeaders); - } - - return callAPI(this._noAuthClient, endpoint, clientParams, options); - } - - callWithInternalUser = (endpoint, clientParams = {}, options = {}) => { - return callAPI(this._client, endpoint, clientParams, options); - } - - getRequestHeadersWhitelist = () => getClonedProperty(this._config, 'requestHeadersWhitelist'); - - getCustomHeaders = () => getClonedProperty(this._config, 'customHeaders'); - - getRequestTimeout = () => getClonedProperty(this._config, 'requestTimeout'); - - getHosts = () => getClonedProperty(this._config, 'hosts'); - - getSsl = () => getClonedProperty(this._config, 'ssl'); - - getClient = () => this._client; - - close() { - for (const client of this._clients) { - client.close(); - } - - this._clients.clear(); - } - - createClient = (configOverrides, parseOptions) => { - const config = { - ...this._getClientConfig(), - ...configOverrides - }; - - const client = new elasticsearch.Client(parseConfig(config, parseOptions)); - this._clients.add(client); - return client; - } - - _getClientConfig = () => { - return getClonedProperties(this._config, [ - 'hosts', - 'ssl', - 'username', - 'password', - 'customHeaders', - 'plugins', - 'apiVersion', - 'keepAlive', - 'pingTimeout', - 'requestTimeout', - 'sniffOnStart', - 'sniffInterval', - 'sniffOnConnectionFault', - 'log' - ]); - } -} - -function callAPI(client, endpoint, clientParams = {}, options = {}) { - const wrap401Errors = options.wrap401Errors !== false; - const clientPath = toPath(endpoint); - const api = get(client, clientPath); - - let apiContext = get(client, clientPath.slice(0, -1)); - if (isEmpty(apiContext)) { - apiContext = client; - } - - if (!api) { - throw new Error(`called with an invalid endpoint: ${endpoint}`); - } - - return api.call(apiContext, clientParams).catch((err) => { - if (!wrap401Errors || err.statusCode !== 401) { - return Promise.reject(err); - } - - const boomError = Boom.boomify(err, { statusCode: err.statusCode }); - const wwwAuthHeader = get(err, 'body.error.header[WWW-Authenticate]'); - boomError.output.headers['WWW-Authenticate'] = wwwAuthHeader || 'Basic realm="Authorization Required"'; - - throw boomError; - }); -} - -function getClonedProperties(config, paths) { - return cloneDeep(paths ? pick(config, paths) : config); -} - -function getClonedProperty(config, path) { - return cloneDeep(path ? get(config, path) : config); -} diff --git a/src/legacy/core_plugins/elasticsearch/lib/cluster.ts b/src/legacy/core_plugins/elasticsearch/lib/cluster.ts new file mode 100644 index 0000000000000..f5ddf25c2d7c2 --- /dev/null +++ b/src/legacy/core_plugins/elasticsearch/lib/cluster.ts @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { errors } from 'elasticsearch'; +import { CallAPIOptions, ClusterClient } from 'kibana'; + +export class Cluster { + public readonly errors = errors; + + constructor(private readonly clusterClient: ClusterClient) {} + + public callWithRequest = async ( + req: { headers?: Record } = {}, + endpoint: string, + clientParams?: Record, + options?: CallAPIOptions + ) => { + return await this.clusterClient + .asScoped(req) + .callAsCurrentUser(endpoint, clientParams, options); + }; + + public callWithInternalUser = async ( + endpoint: string, + clientParams?: Record, + options?: CallAPIOptions + ) => { + return await this.clusterClient.callAsInternalUser(endpoint, clientParams, options); + }; + + public close() { + this.clusterClient.close(); + } +} diff --git a/src/legacy/core_plugins/elasticsearch/lib/health_check.js b/src/legacy/core_plugins/elasticsearch/lib/health_check.js index 4be5ea8890c30..304f3b816214c 100644 --- a/src/legacy/core_plugins/elasticsearch/lib/health_check.js +++ b/src/legacy/core_plugins/elasticsearch/lib/health_check.js @@ -18,23 +18,20 @@ */ import Promise from 'bluebird'; -import elasticsearch from 'elasticsearch'; import kibanaVersion from './kibana_version'; import { ensureEsVersion } from './ensure_es_version'; -const NoConnections = elasticsearch.errors.NoConnections; - -export default function (plugin, server) { - const config = server.config(); - const callAdminAsKibanaUser = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser; - const REQUEST_DELAY = config.get('elasticsearch.healthCheck.delay'); +export default function (plugin, server, requestDelay) { + const adminCluster = server.plugins.elasticsearch.getCluster('admin'); + const NoConnections = adminCluster.errors.NoConnections; + const callAdminAsKibanaUser = adminCluster.callWithInternalUser; plugin.status.yellow('Waiting for Elasticsearch'); function waitForPong(callWithInternalUser) { return callWithInternalUser('ping').catch(function (err) { if (!(err instanceof NoConnections)) throw err; plugin.status.red(`Unable to connect to Elasticsearch.`); - return Promise.delay(REQUEST_DELAY).then(waitForPong.bind(null, callWithInternalUser)); + return Promise.delay(requestDelay).then(waitForPong.bind(null, callWithInternalUser)); }); } @@ -47,7 +44,7 @@ export default function (plugin, server) { function waitForEsVersion() { return ensureEsVersion(server, kibanaVersion.get()).catch(err => { plugin.status.red(err); - return Promise.delay(REQUEST_DELAY).then(waitForEsVersion); + return Promise.delay(requestDelay).then(waitForEsVersion); }); } @@ -81,7 +78,7 @@ export default function (plugin, server) { } function startorRestartChecking() { - scheduleCheck(stopChecking() ? REQUEST_DELAY : 1); + scheduleCheck(stopChecking() ? requestDelay : 1); } function stopChecking() { diff --git a/src/legacy/core_plugins/elasticsearch/lib/map_uri.js b/src/legacy/core_plugins/elasticsearch/lib/map_uri.js deleted file mode 100644 index 4566ed03df6e1..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/map_uri.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 { defaults, omit, trimLeft, trimRight } from 'lodash'; -import { parse as parseUrl, format as formatUrl } from 'url'; -import filterHeaders from './filter_headers'; -import setHeaders from './set_headers'; - -export default function mapUri(cluster, proxyPrefix) { - function joinPaths(pathA, pathB) { - return trimRight(pathA, '/') + '/' + trimLeft(pathB, '/'); - } - - return function (request) { - const { - protocol: esUrlProtocol, - slashes: esUrlHasSlashes, - auth: esUrlAuth, - hostname: esUrlHostname, - port: esUrlPort, - pathname: esUrlBasePath, - query: esUrlQuery - } = parseUrl(cluster.getUrl(), true); - - // copy most url components directly from elasticsearch.hosts - const mappedUrlComponents = { - protocol: esUrlProtocol, - slashes: esUrlHasSlashes, - auth: esUrlAuth, - hostname: esUrlHostname, - port: esUrlPort - }; - - // pathname - const reqSubPath = request.path.replace(proxyPrefix, ''); - mappedUrlComponents.pathname = joinPaths(esUrlBasePath, reqSubPath); - - // querystring - const mappedQuery = defaults(omit(request.query, '_'), esUrlQuery); - if (Object.keys(mappedQuery).length) { - mappedUrlComponents.query = mappedQuery; - } - - const filteredHeaders = filterHeaders(request.headers, cluster.getRequestHeadersWhitelist()); - const mappedHeaders = setHeaders(filteredHeaders, cluster.getCustomHeaders()); - const mappedUrl = formatUrl(mappedUrlComponents); - return { uri: mappedUrl, headers: mappedHeaders }; - }; -} diff --git a/src/legacy/core_plugins/elasticsearch/lib/parse_config.js b/src/legacy/core_plugins/elasticsearch/lib/parse_config.js deleted file mode 100644 index dc77452011161..0000000000000 --- a/src/legacy/core_plugins/elasticsearch/lib/parse_config.js +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 util from 'util'; -import url from 'url'; -import { get, noop, size, pick } from 'lodash'; -import { readFileSync } from 'fs'; -import Bluebird from 'bluebird'; - -const readFile = (file) => readFileSync(file, 'utf8'); - -export function parseConfig(serverConfig = {}, { ignoreCertAndKey = false } = {}) { - const config = { - keepAlive: true, - ...pick(serverConfig, [ - 'plugins', 'apiVersion', 'keepAlive', 'pingTimeout', - 'requestTimeout', 'log', 'logQueries', 'sniffOnStart', - 'sniffInterval', 'sniffOnConnectionFault', 'hosts' - ]) - }; - - const mapHost = nodeUrl => { - const uri = url.parse(nodeUrl); - const httpsURI = uri.protocol === 'https:'; - const httpURI = uri.protocol === 'http:'; - const protocolPort = httpsURI && '443' || httpURI && '80'; - return { - host: uri.hostname, - port: uri.port || protocolPort, - protocol: uri.protocol, - path: uri.pathname, - query: uri.query, - headers: serverConfig.customHeaders - }; - }; - - if (serverConfig.hosts) { - config.hosts = serverConfig.hosts.map(mapHost); - } - - // Auth - if (serverConfig.auth !== false && serverConfig.username && serverConfig.password) { - config.hosts.forEach(host => { - host.auth = util.format('%s:%s', serverConfig.username, serverConfig.password); - }); - } - - // SSL - config.ssl = {}; - - const verificationMode = get(serverConfig, 'ssl.verificationMode'); - switch (verificationMode) { - case 'none': - config.ssl.rejectUnauthorized = false; - break; - case 'certificate': - config.ssl.rejectUnauthorized = true; - - // by default, NodeJS is checking the server identify - config.ssl.checkServerIdentity = noop; - break; - case 'full': - config.ssl.rejectUnauthorized = true; - break; - default: - throw new Error(`Unknown ssl verificationMode: ${verificationMode}`); - } - - if (size(get(serverConfig, 'ssl.certificateAuthorities'))) { - config.ssl.ca = serverConfig.ssl.certificateAuthorities.map(readFile); - } - - // Add client certificate and key if required by elasticsearch - if (!ignoreCertAndKey && get(serverConfig, 'ssl.certificate') && get(serverConfig, 'ssl.key')) { - config.ssl.cert = readFile(serverConfig.ssl.certificate); - config.ssl.key = readFile(serverConfig.ssl.key); - config.ssl.passphrase = serverConfig.ssl.keyPassphrase; - } - - config.defer = () => Bluebird.defer(); - - return config; -} diff --git a/src/legacy/core_plugins/inspector_views/public/requests/request_selector.js b/src/legacy/core_plugins/inspector_views/public/requests/request_selector.js index abb45a3204481..6801c9e6d6ec7 100644 --- a/src/legacy/core_plugins/inspector_views/public/requests/request_selector.js +++ b/src/legacy/core_plugins/inspector_views/public/requests/request_selector.js @@ -116,6 +116,7 @@ class RequestSelector extends Component { > ); @@ -140,7 +141,7 @@ class RequestSelector extends Component { {requests.length <= 1 && -
+
{selectedRequest.name}
} diff --git a/src/legacy/core_plugins/interpreter/common/constants.js b/src/legacy/core_plugins/interpreter/common/constants.js index a5751ee72e826..38e30e7f9236b 100644 --- a/src/legacy/core_plugins/interpreter/common/constants.js +++ b/src/legacy/core_plugins/interpreter/common/constants.js @@ -17,5 +17,4 @@ * under the License. */ -export const SECURITY_AUTH_MESSAGE = 'Authentication failed'; export const API_ROUTE = '/api/canvas'; diff --git a/src/legacy/core_plugins/interpreter/init.js b/src/legacy/core_plugins/interpreter/init.js index a4b702b3cdbe9..68cc6c9c47c88 100644 --- a/src/legacy/core_plugins/interpreter/init.js +++ b/src/legacy/core_plugins/interpreter/init.js @@ -33,8 +33,6 @@ export default async function (server /*options*/) { return { kbnIndex: config.get('kibana.index'), - esShardTimeout: config.get('elasticsearch.shardTimeout'), - esApiVersion: config.get('elasticsearch.apiVersion'), serverFunctions: registries.serverFunctions.toArray(), basePath, reportingBrowserType, diff --git a/src/legacy/core_plugins/interpreter/public/interpreter.js b/src/legacy/core_plugins/interpreter/public/interpreter.js index 1ec5b00d39526..b26f46f7a27ee 100644 --- a/src/legacy/core_plugins/interpreter/public/interpreter.js +++ b/src/legacy/core_plugins/interpreter/public/interpreter.js @@ -20,6 +20,7 @@ import { register } from '@kbn/interpreter/common'; import { initializeInterpreter, registries } from '@kbn/interpreter/public'; import { kfetch } from 'ui/kfetch'; +import { ajaxStream } from 'ui/ajax_stream'; import { functions } from './functions'; import { visualization } from './renderers/visualization'; @@ -32,7 +33,12 @@ let _resolve; let _interpreterPromise; const initialize = async () => { - initializeInterpreter(kfetch, registries.types, registries.browserFunctions).then(interpreter => { + initializeInterpreter({ + kfetch, + ajaxStream, + typesRegistry: registries.types, + functionsRegistry: registries.browserFunctions, + }).then(interpreter => { _resolve({ interpreter }); }); }; diff --git a/src/legacy/core_plugins/interpreter/server/lib/__tests__/create_handlers.js b/src/legacy/core_plugins/interpreter/server/lib/__tests__/create_handlers.js index 8f118eec7fb9c..948ec7369d631 100644 --- a/src/legacy/core_plugins/interpreter/server/lib/__tests__/create_handlers.js +++ b/src/legacy/core_plugins/interpreter/server/lib/__tests__/create_handlers.js @@ -19,12 +19,6 @@ import expect from 'expect.js'; import { createHandlers } from '../create_handlers'; -import { SECURITY_AUTH_MESSAGE } from '../../../common/constants'; - -let securityMode = 'pass'; -let isSecurityAvailable = true; -let isSecurityEnabled = true; -const authError = new Error('auth error'); const mockRequest = { headers: 'i can haz headers', @@ -32,26 +26,11 @@ const mockRequest = { const mockServer = { plugins: { - security: { - authenticate: () => ({ - succeeded: () => (securityMode === 'pass' ? true : false), - error: securityMode === 'pass' ? null : authError, - }), - }, elasticsearch: { getCluster: () => ({ callWithRequest: (...args) => Promise.resolve(args), }), }, - // TODO: remove this when we use the method exposed by security https://github.com/elastic/kibana/pull/24616 - xpack_main: { - info: { - feature: () => ({ - isAvailable: () => isSecurityAvailable, - isEnabled: () => isSecurityEnabled, - }), - }, - }, }, config: () => ({ has: () => false, @@ -63,16 +42,9 @@ const mockServer = { }; describe('server createHandlers', () => { - let handlers; - - beforeEach(() => { - securityMode = 'pass'; - isSecurityEnabled = true; - isSecurityAvailable = true; - handlers = createHandlers(mockRequest, mockServer); - }); - it('provides helper methods and properties', () => { + const handlers = createHandlers(mockRequest, mockServer); + expect(handlers).to.have.property('environment', 'server'); expect(handlers).to.have.property('serverUri'); expect(handlers).to.have.property('elasticsearchClient'); @@ -80,78 +52,7 @@ describe('server createHandlers', () => { describe('elasticsearchClient', () => { it('executes callWithRequest', async () => { - const [request, endpoint, payload] = await handlers.elasticsearchClient( - 'endpoint', - 'payload' - ); - expect(request).to.equal(mockRequest); - expect(endpoint).to.equal('endpoint'); - expect(payload).to.equal('payload'); - }); - - it('rejects when authentication check fails', () => { - securityMode = 'fail'; - return handlers - .elasticsearchClient('endpoint', 'payload') - .then(() => { - throw new Error('elasticsearchClient should fail when authentication fails'); - }) - .catch(err => { - expect(err.message).to.be.equal(SECURITY_AUTH_MESSAGE); - }); - }); - - it('works without security plugin in kibana', async () => { - // create server without security plugin - const mockServerClone = { - ...mockServer, - plugins: { ...mockServer.plugins }, - }; - delete mockServerClone.plugins.security; - expect(mockServer.plugins).to.have.property('security'); // confirm original server object - expect(mockServerClone.plugins).to.not.have.property('security'); - - // this shouldn't do anything - securityMode = 'fail'; - - // make sure the method still works - handlers = createHandlers(mockRequest, mockServerClone); - const [request, endpoint, payload] = await handlers.elasticsearchClient( - 'endpoint', - 'payload' - ); - expect(request).to.equal(mockRequest); - expect(endpoint).to.equal('endpoint'); - expect(payload).to.equal('payload'); - }); - - it('works without security available', async () => { - // create server with security unavailable (i.e. when user is on a basic license) - isSecurityAvailable = false; - - // this shouldn't do anything - securityMode = 'fail'; - - // make sure the method still works - handlers = createHandlers(mockRequest, mockServer); - const [request, endpoint, payload] = await handlers.elasticsearchClient( - 'endpoint', - 'payload' - ); - expect(request).to.equal(mockRequest); - expect(endpoint).to.equal('endpoint'); - expect(payload).to.equal('payload'); - }); - - it('works with security disabled in elasticsearch', async () => { - // create server with security disabled - isSecurityEnabled = false; - - // this shouldn't do anything - securityMode = 'fail'; - - // make sure the method still works - handlers = createHandlers(mockRequest, mockServer); + const handlers = createHandlers(mockRequest, mockServer); const [request, endpoint, payload] = await handlers.elasticsearchClient( 'endpoint', 'payload' diff --git a/src/legacy/core_plugins/interpreter/server/lib/create_handlers.js b/src/legacy/core_plugins/interpreter/server/lib/create_handlers.js index be51d55680c49..d4ea9b3dc6180 100644 --- a/src/legacy/core_plugins/interpreter/server/lib/create_handlers.js +++ b/src/legacy/core_plugins/interpreter/server/lib/create_handlers.js @@ -17,10 +17,6 @@ * under the License. */ -import boom from 'boom'; -import { isSecurityEnabled } from './feature_check'; -import { SECURITY_AUTH_MESSAGE } from '../../common/constants'; - export const createHandlers = (request, server) => { const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); const config = server.config(); @@ -31,27 +27,6 @@ export const createHandlers = (request, server) => { config.has('server.rewriteBasePath') && config.get('server.rewriteBasePath') ? `${server.info.uri}${config.get('server.basePath')}` : server.info.uri, - elasticsearchClient: async (...args) => { - // check if the session is valid because continuing to use it - if (isSecurityEnabled(server)) { - try { - const authenticationResult = await server.plugins.security.authenticate(request); - if (!authenticationResult.succeeded()) { - throw boom.unauthorized(authenticationResult.error); - } - } catch (e) { - // if authenticate throws, show error in development - if (process.env.NODE_ENV !== 'production') { - e.message = `elasticsearchClient failed: ${e.message}`; - console.error(e); - } - - // hide all failure information from the user - throw boom.unauthorized(SECURITY_AUTH_MESSAGE); - } - } - - return callWithRequest(request, ...args); - }, + elasticsearchClient: async (...args) => callWithRequest(request, ...args), }; }; diff --git a/src/legacy/core_plugins/interpreter/server/lib/route_expression/index.js b/src/legacy/core_plugins/interpreter/server/lib/route_expression/index.js deleted file mode 100644 index 7098572ce2b46..0000000000000 --- a/src/legacy/core_plugins/interpreter/server/lib/route_expression/index.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 { createError } from '@kbn/interpreter/common'; - -export const routeExpressionProvider = environments => { - async function routeExpression(ast, context = null) { - // List of environments in order of preference - - return Promise.all(environments).then(async environments => { - const environmentFunctions = await Promise.all(environments.map(env => env.getFunctions())); - - // Grab name of the first function in the chain - const fnName = ast.chain[0].function.toLowerCase(); - - // Check each environment for that function - for (let i = 0; i < environmentFunctions.length; i++) { - if (environmentFunctions[i].includes(fnName)) { - // If we find it, run in that environment, and only that environment - return environments[i].interpret(ast, context).catch(e => createError(e)); - } - } - - // If the function isn't found in any environment, give up - throw new Error(`Function not found: [${fnName}]`); - }); - } - - return routeExpression; -}; diff --git a/src/legacy/core_plugins/interpreter/server/lib/route_expression/server.js b/src/legacy/core_plugins/interpreter/server/lib/route_expression/server.js deleted file mode 100644 index 7b063e1366ff8..0000000000000 --- a/src/legacy/core_plugins/interpreter/server/lib/route_expression/server.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 { interpreterProvider } from '@kbn/interpreter/common'; -import { createHandlers } from '../create_handlers'; - -export const server = async ({ server, request }) => { - const { serverFunctions, types } = server.plugins.interpreter.registries(); - - return { - interpret: (ast, context) => { - const interpret = interpreterProvider({ - types: types.toJS(), - functions: serverFunctions.toJS(), - handlers: createHandlers(request, server), - }); - - return interpret(ast, context); - }, - getFunctions: () => Object.keys(serverFunctions.toJS()), - }; -}; diff --git a/src/legacy/core_plugins/interpreter/server/routes/index.js b/src/legacy/core_plugins/interpreter/server/routes/index.js index b691abbad133b..9140f93a9bde6 100644 --- a/src/legacy/core_plugins/interpreter/server/routes/index.js +++ b/src/legacy/core_plugins/interpreter/server/routes/index.js @@ -17,10 +17,8 @@ * under the License. */ -import { translate } from './translate'; import { registerServerFunctions } from './server_functions'; export function routes(server) { - translate(server); registerServerFunctions(server); } diff --git a/src/legacy/core_plugins/interpreter/server/routes/server_functions.js b/src/legacy/core_plugins/interpreter/server/routes/server_functions.js index a0fe045cd49bd..cdd552e258ca9 100644 --- a/src/legacy/core_plugins/interpreter/server/routes/server_functions.js +++ b/src/legacy/core_plugins/interpreter/server/routes/server_functions.js @@ -43,6 +43,10 @@ function runServerFunctions(server) { method: 'POST', path: `${API_ROUTE}/fns`, options: { + payload: { + allow: 'application/json', + maxBytes: 26214400, // 25MB payload limit + }, validate: { payload: Joi.object({ functions: Joi.array().items( @@ -61,37 +65,64 @@ function runServerFunctions(server) { const handlers = await createHandlers(req, server); const { functions } = req.payload; - // Process each function individually, and bundle up respones / errors into - // the format expected by the front-end batcher. - const results = await Promise.all(functions.map(async ({ id, ...fnCall }) => { - const result = await runFunction(server, handlers, fnCall) - .catch(err => { - if (Boom.isBoom(err)) { - return { err, statusCode: err.statusCode, message: err.output.payload }; - } - return { err: 'Internal Server Error', statusCode: 500, message: 'See server logs for details.' }; - }); - - if (result == null) { - const { functionName } = fnCall; - return { - id, - result: { - err: `No result from '${functionName}'`, - statusCode: 500, - message: `Function '${functionName}' did not return anything` - } - }; + // Grab the raw Node response object. + const res = req.raw.res; + + // Tell Hapi not to manage the response https://github.com/hapijs/hapi/issues/3884 + req._isReplied = true; + + // Send the initial headers. + res.writeHead(200, { + 'Content-Type': 'text/plain', + 'Connection': 'keep-alive', + 'Transfer-Encoding': 'chunked', + 'Cache-Control': 'no-cache', + }); + + // Write a length-delimited response + const streamResult = (result) => { + const payload = JSON.stringify(result) + '\n'; + res.write(`${payload.length}:${payload}`); + }; + + // Tries to run an interpreter function, and ensures a consistent error payload on failure. + const tryFunction = async (id, fnCall) => { + try { + const result = await runFunction(server, handlers, fnCall); + + if (result != null) { + return { id, statusCode: 200, result }; + } + + return batchError(id, `Function ${fnCall.functionName} did not return anything.`); + } catch (err) { + if (Boom.isBoom(err)) { + return batchError(id, err.output.payload, err.statusCode); + } + return batchError(id, 'See server logs for details.'); } + }; - return { id, result }; - })); + // Process each function individually, and stream the responses back to the client + await Promise.all(functions.map(({ id, ...fnCall }) => tryFunction(id, fnCall).then(streamResult))); - return { results }; + // All of the responses have been written, so we can close the response. + res.end(); }, }); } +/** + * A helper function for bundling up errors. + */ +function batchError(id, message, statusCode = 500) { + return { + id, + statusCode, + result: { statusCode, message }, + }; +} + /** * Register the endpoint that returns the list of server-only functions. * @param {*} server - The Kibana server diff --git a/src/legacy/core_plugins/interpreter/server/routes/translate.js b/src/legacy/core_plugins/interpreter/server/routes/translate.js deleted file mode 100644 index 01cd2a2401167..0000000000000 --- a/src/legacy/core_plugins/interpreter/server/routes/translate.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you 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 { fromExpression, toExpression } from '@kbn/interpreter/common'; - -export function translate(server) { - /* - Get AST from expression - */ - server.route({ - method: 'GET', - path: '/api/canvas/ast', - handler: function (request, h) { - if (!request.query.expression) { - return h.response({ error: '"expression" query is required' }).code(400); - } - return fromExpression(request.query.expression); - }, - }); - - server.route({ - method: 'POST', - path: '/api/canvas/expression', - handler: function (request, h) { - try { - return toExpression(request.payload); - } catch (e) { - return h.response({ error: e.message }).code(400); - } - }, - }); -} diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html index 375cd0fe3b205..f5f838f5b0f5b 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html @@ -28,6 +28,18 @@
+ + + {this.props.isProcessing ? {this.props.isProcessing ? { it('should throw an error when requesting a component that does not exist', () => { expect(() => getSettingsComponent('does not exist')).toThrowErrorMatchingSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.js index 41979d4bd66a6..80b2f2e79b9c7 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.js @@ -30,4 +30,4 @@ export function registerDefaultComponents() { tryRegisterSettingsComponent(PAGE_TITLE_COMPONENT, PageTitle); tryRegisterSettingsComponent(PAGE_SUBTITLE_COMPONENT, PageSubtitle); tryRegisterSettingsComponent(PAGE_FOOTER_COMPONENT, PageFooter); -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.js index 2c5b3c9b46613..4fc6dc710f866 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.js @@ -40,4 +40,4 @@ describe('default_component_registry', () => { expect(getSettingsComponent(PAGE_TITLE_COMPONENT)).toEqual(newComponent); }); -}); \ No newline at end of file +}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/index.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/index.js index 2fae89ceb0380..762f61984d0a1 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/index.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/index.js @@ -17,4 +17,4 @@ * under the License. */ -export { PageFooter } from './page_footer'; \ No newline at end of file +export { PageFooter } from './page_footer'; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.js index e55fbbae3b5f8..5c769c5d51e5a 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.js @@ -17,4 +17,4 @@ * under the License. */ -export const PageFooter = () => null; \ No newline at end of file +export const PageFooter = () => null; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.test.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.test.js index 1f8af7f0d6e93..eb561517d61b3 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.test.js @@ -25,4 +25,4 @@ describe('PageFooter', () => { it('should render normally', () => { expect(shallowWithIntl()).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.js index 35485fdc7b492..1b688d7f20307 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.js @@ -17,4 +17,4 @@ * under the License. */ -export const PageSubtitle = () => null; \ No newline at end of file +export const PageSubtitle = () => null; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.test.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.test.js index cb1e785ac3043..999d6a2143f4c 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.test.js @@ -25,4 +25,4 @@ describe('PageSubtitle', () => { it('should render normally', () => { expect(shallowWithIntl()).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/index.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/index.js index f5553eb971ac3..1afa42277294d 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/index.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/index.js @@ -17,4 +17,4 @@ * under the License. */ -export { PageTitle } from './page_title'; \ No newline at end of file +export { PageTitle } from './page_title'; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.js index 48407faea8cb3..fb73154159c92 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.js @@ -34,4 +34,4 @@ export const PageTitle = () => { ); -}; \ No newline at end of file +}; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.test.js b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.test.js index 16fa30cd90c0e..261f892c22f45 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.test.js @@ -25,4 +25,4 @@ describe('PageTitle', () => { it('should render normally', () => { expect(shallowWithIntl()).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/src/legacy/ui/public/embeddable/get_index_pattern.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts similarity index 100% rename from src/legacy/ui/public/embeddable/get_index_pattern.ts rename to src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.ts index 26e565a636e30..e7a81a61b9831 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.ts @@ -26,9 +26,9 @@ import { EmbeddableInstanceConfiguration, OnEmbeddableStateChanged, } from 'ui/embeddable/embeddable_factory'; -import { getIndexPattern } from 'ui/embeddable/get_index_pattern'; import { SavedVisualizations } from '../types'; import { DisabledLabEmbeddable } from './disabled_lab_embeddable'; +import { getIndexPattern } from './get_index_pattern'; export class VisualizeEmbeddableFactory extends EmbeddableFactory { private savedVisualizations: SavedVisualizations; diff --git a/src/legacy/core_plugins/kibana/server/lib/export/collect_references_deep.test.ts b/src/legacy/core_plugins/kibana/server/lib/export/collect_references_deep.test.ts index 390f6a6087259..282730ad0e4db 100644 --- a/src/legacy/core_plugins/kibana/server/lib/export/collect_references_deep.test.ts +++ b/src/legacy/core_plugins/kibana/server/lib/export/collect_references_deep.test.ts @@ -17,7 +17,10 @@ * under the License. */ -import { SavedObject } from '../../../../../server/saved_objects/service/saved_objects_client'; +import { + SavedObject, + SavedObjectsClient, +} from '../../../../../server/saved_objects/service/saved_objects_client'; import { collectReferencesDeep } from './collect_references_deep'; const data = [ @@ -100,7 +103,7 @@ const data = [ ]; test('collects dashboard and all dependencies', async () => { - const savedObjectClient = { + const savedObjectClient = ({ errors: {} as any, create: jest.fn(), bulkCreate: jest.fn(), @@ -115,7 +118,7 @@ test('collects dashboard and all dependencies', async () => { ), }; }), - }; + } as unknown) as SavedObjectsClient; const objects = await collectReferencesDeep(savedObjectClient, [{ type: 'dashboard', id: '1' }]); expect(objects).toMatchInlineSnapshot(` Array [ diff --git a/src/legacy/core_plugins/kibana/server/tutorials/register.js b/src/legacy/core_plugins/kibana/server/tutorials/register.js index 9fef466fe3108..1f0b39fef0e59 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/register.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/register.js @@ -67,6 +67,7 @@ import { awsMetricsSpecProvider } from './aws_metrics'; import { mssqlMetricsSpecProvider } from './mssql_metrics'; import { natsMetricsSpecProvider } from './nats_metrics'; import { natsLogsSpecProvider } from './nats_logs'; +import { zeekLogsSpecProvider } from './zeek_logs'; export function registerTutorials(server) { server.registerTutorial(systemLogsSpecProvider); @@ -119,4 +120,5 @@ export function registerTutorials(server) { server.registerTutorial(mssqlMetricsSpecProvider); server.registerTutorial(natsMetricsSpecProvider); server.registerTutorial(natsLogsSpecProvider); + server.registerTutorial(zeekLogsSpecProvider); } diff --git a/src/legacy/core_plugins/kibana/server/tutorials/zeek_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/zeek_logs/index.js new file mode 100644 index 0000000000000..6086f3cbde0b1 --- /dev/null +++ b/src/legacy/core_plugins/kibana/server/tutorials/zeek_logs/index.js @@ -0,0 +1,65 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { i18n } from '@kbn/i18n'; +import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; +import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; + +export function zeekLogsSpecProvider(server, context) { + const moduleName = 'zeek'; + const platforms = ['OSX', 'DEB', 'RPM']; + return { + id: 'zeekLogs', + name: i18n.translate('kbn.server.tutorials.zeekLogs.nameTitle', { + defaultMessage: 'Zeek logs', + }), + category: TUTORIAL_CATEGORY.SECURITY, + shortDescription: i18n.translate('kbn.server.tutorials.zeekLogs.shortDescription', { + defaultMessage: 'Collect the logs created by Zeek/Bro.', + }), + longDescription: i18n.translate('kbn.server.tutorials.zeekLogs.longDescription', { + defaultMessage: 'The `zeek` Filebeat module collects the logs from \ +[Zeek](https://www.zeek.org//documentation/index.html). \ +[Learn more]({learnMoreLink}).', + values: { + learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-zeek.html', + }, + }), + //TODO: euiIconType: 'logoZeek', + artifacts: { + dashboards: [ + { + id: '7cbb5410-3700-11e9-aa6d-ff445a78330c', + linkLabel: i18n.translate('kbn.server.tutorials.zeekLogs.artifacts.dashboards.linkLabel', { + defaultMessage: 'Zeek logs dashboard', + }), + isOverview: true + } + ], + exportedFields: { + documentationUrl: '{config.docs.beats.filebeat}/exported-fields-zeek.html' + } + }, + completionTimeMinutes: 10, + previewImagePath: '/plugins/kibana/home/tutorial_resources/zeek_logs/screenshot.png', + onPrem: onPremInstructions(moduleName, platforms, context), + elasticCloud: cloudInstructions(moduleName, platforms), + onPremElasticCloud: onPremCloudInstructions(moduleName, platforms) + }; +} diff --git a/src/legacy/core_plugins/metrics/index.js b/src/legacy/core_plugins/metrics/index.js index 1258cedf8c7f1..b0b3dbb8377e0 100644 --- a/src/legacy/core_plugins/metrics/index.js +++ b/src/legacy/core_plugins/metrics/index.js @@ -21,6 +21,7 @@ import { resolve } from 'path'; import fieldsRoutes from './server/routes/fields'; import visDataRoutes from './server/routes/vis'; +import { SearchStrategiesRegister } from './server/lib/search_strategies/search_strategies_register'; export default function (kibana) { return new kibana.Plugin({ @@ -28,7 +29,7 @@ export default function (kibana) { uiExports: { visTypes: [ - 'plugins/metrics/kbn_vis_types' + 'plugins/metrics/kbn_vis_types', ], styleSheetPaths: resolve(__dirname, 'public/index.scss'), }, @@ -37,16 +38,15 @@ export default function (kibana) { return Joi.object({ enabled: Joi.boolean().default(true), chartResolution: Joi.number().default(150), - minimumBucketSize: Joi.number().default(10) + minimumBucketSize: Joi.number().default(10), }).default(); }, - init(server) { fieldsRoutes(server); visDataRoutes(server); - } - + SearchStrategiesRegister.init(server); + }, }); } diff --git a/src/legacy/core_plugins/metrics/public/components/_error.scss b/src/legacy/core_plugins/metrics/public/components/_error.scss index 0718bf58b0ce2..efe378bb791c2 100644 --- a/src/legacy/core_plugins/metrics/public/components/_error.scss +++ b/src/legacy/core_plugins/metrics/public/components/_error.scss @@ -1,15 +1,16 @@ -.tvbError__additional, -.tvbError__stack { - margin-top: $euiSizeS; -} - -// EUITODO: Convert to EuiCodeBlock -.tvbError__stack { - padding: $euiSizeS; - background: $euiCodeBlockBackgroundColor; - color: $euiCodeBlockColor; - line-height: $euiLineHeight; - font-family: $euiCodeFontFamily; - font-weight: $euiFontWeightRegular; - white-space: pre-wrap; -} +.tvbError__title, +.tvbError__additional, +.tvbError__stack { + margin-top: $euiSizeS; +} + +// EUITODO: Convert to EuiCodeBlock +.tvbError__stack { + padding: $euiSizeS; + background: $euiCodeBlockBackgroundColor; + color: $euiCodeBlockColor; + line-height: $euiLineHeight; + font-family: $euiCodeFontFamily; + font-weight: $euiFontWeightRegular; + white-space: pre-wrap; +} diff --git a/src/legacy/core_plugins/metrics/public/components/aggs/percentile.js b/src/legacy/core_plugins/metrics/public/components/aggs/percentile.js index 4bf29f681df9e..a7b1d2b4c251d 100644 --- a/src/legacy/core_plugins/metrics/public/components/aggs/percentile.js +++ b/src/legacy/core_plugins/metrics/public/components/aggs/percentile.js @@ -46,11 +46,6 @@ const newPercentile = (opts) => { class PercentilesUi extends Component { - constructor(props) { - super(props); - this.renderRow = this.renderRow.bind(this); - } - handleTextChange(item, name) { return (e) => { const handleChange = collectionActions.handleChange.bind(null, this.props); @@ -60,12 +55,29 @@ class PercentilesUi extends Component { }; } - renderRow(row, i, items) { + renderRow = (row, i, items) => { const defaults = { value: '', percentile: '', shade: '' }; const model = { ...defaults, ...row }; + const { intl, panel } = this.props; + + const percentileFieldNumber = ( + + + + ); + + if (panel.type === 'table') { + return percentileFieldNumber; + } + const handleAdd = collectionActions.handleAdd.bind(null, this.props, newPercentile); const handleDelete = collectionActions.handleDelete.bind(null, this.props, model); - const { intl } = this.props; const modeOptions = [ { label: intl.formatMessage({ id: 'tsvb.percentile.modeOptions.lineLabel', defaultMessage: 'Line' }), @@ -88,15 +100,8 @@ class PercentilesUi extends Component { return ( - - - + + { percentileFieldNumber } @@ -167,10 +172,15 @@ class PercentilesUi extends Component { } render() { - const { model, name } = this.props; + const { model, name, panel } = this.props; if (!model[name]) return (
); + let rows; + if (panel.type === 'table') { + rows = this.renderRow(_.last(model[name])); + } else { + rows = model[name].map(this.renderRow); + } - const rows = model[name].map(this.renderRow); return ( { rows } @@ -186,6 +196,7 @@ PercentilesUi.defaultProps = { PercentilesUi.propTypes = { name: PropTypes.string, model: PropTypes.object, + panel: PropTypes.object, onChange: PropTypes.func }; @@ -259,6 +270,7 @@ class PercentileAgg extends Component { // eslint-disable-line react/no-multi-co onChange={handleChange} name="percentiles" model={model} + panel={panel} /> diff --git a/src/legacy/core_plugins/metrics/public/components/error.js b/src/legacy/core_plugins/metrics/public/components/error.js index e06d2eaa3ea82..bc3272605e579 100644 --- a/src/legacy/core_plugins/metrics/public/components/error.js +++ b/src/legacy/core_plugins/metrics/public/components/error.js @@ -23,10 +23,12 @@ import React from 'react'; import _ from 'lodash'; import { FormattedMessage } from '@kbn/i18n/react'; +const guidPattern = /\[[[a-f\d-\\]{36}\]/g; + function ErrorComponent(props) { const { error } = props; let additionalInfo; - const type = _.get(error, 'error.caused_by.type'); + const type = _.get(error, 'error.caused_by.type') || _.get(error, 'error.type'); let reason = _.get(error, 'error.caused_by.reason'); const title = _.get(error, 'error.caused_by.title'); @@ -34,6 +36,10 @@ function ErrorComponent(props) { reason = _.get(error, 'message'); } + if (['runtime_exception', 'illegal_argument_exception'].includes(type)) { + reason = _.get(error, 'error.reason').replace(guidPattern, ``); + } + if (type === 'script_exception') { const scriptStack = _.get(error, 'error.caused_by.script_stack'); reason = _.get(error, 'error.caused_by.caused_by.reason'); diff --git a/src/legacy/core_plugins/metrics/public/components/index_pattern.js b/src/legacy/core_plugins/metrics/public/components/index_pattern.js index dc456026acb5a..ae5321c95337c 100644 --- a/src/legacy/core_plugins/metrics/public/components/index_pattern.js +++ b/src/legacy/core_plugins/metrics/public/components/index_pattern.js @@ -44,6 +44,7 @@ export const IndexPattern = props => { const dropBucketName = `${prefix}drop_last_bucket`; const defaults = { + default_index_pattern: '', [indexPatternName]: '*', [intervalName]: 'auto', [dropBucketName]: 1 @@ -62,11 +63,16 @@ export const IndexPattern = props => { id="tsvb.indexPatternLabel" defaultMessage="Index pattern" />)} + helpText={(model.default_index_pattern && !model[indexPatternName] && )} fullWidth > { return handleChange({ [name]: value }); } }; -}; \ No newline at end of file +}; diff --git a/src/legacy/core_plugins/metrics/public/components/lib/create_text_handler.js b/src/legacy/core_plugins/metrics/public/components/lib/create_text_handler.js index 542479cbe8772..ca2711da9fd81 100644 --- a/src/legacy/core_plugins/metrics/public/components/lib/create_text_handler.js +++ b/src/legacy/core_plugins/metrics/public/components/lib/create_text_handler.js @@ -30,4 +30,4 @@ export default (handleChange) => { return handleChange({ [name]: value }); } }; -}; \ No newline at end of file +}; diff --git a/src/legacy/core_plugins/metrics/public/components/lib/detect_ie.js b/src/legacy/core_plugins/metrics/public/components/lib/detect_ie.js index a0a7d2b72962d..e1ac8747bc8ce 100644 --- a/src/legacy/core_plugins/metrics/public/components/lib/detect_ie.js +++ b/src/legacy/core_plugins/metrics/public/components/lib/detect_ie.js @@ -41,4 +41,4 @@ export function detectIE() { // other browser return false; -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/metrics/public/components/splits/terms.js b/src/legacy/core_plugins/metrics/public/components/splits/terms.js index 2e50031635f18..5ca25ba775846 100644 --- a/src/legacy/core_plugins/metrics/public/components/splits/terms.js +++ b/src/legacy/core_plugins/metrics/public/components/splits/terms.js @@ -158,4 +158,4 @@ SplitByTermsUi.propTypes = { fields: PropTypes.object }; -export const SplitByTerms = injectI18n(SplitByTermsUi); \ No newline at end of file +export const SplitByTerms = injectI18n(SplitByTermsUi); diff --git a/src/legacy/core_plugins/metrics/public/components/vis_editor.js b/src/legacy/core_plugins/metrics/public/components/vis_editor.js index d52fbb1657403..ece210a82b8b9 100644 --- a/src/legacy/core_plugins/metrics/public/components/vis_editor.js +++ b/src/legacy/core_plugins/metrics/public/components/vis_editor.js @@ -72,13 +72,12 @@ class VisEditor extends Component { } setDefaultIndexPattern = async () => { - if (this.props.vis.params.index_pattern === '') { - // set the default index pattern if none is defined. - const savedObjectsClient = chrome.getSavedObjectsClient(); - const indexPattern = await savedObjectsClient.get('index-pattern', this.getConfig('defaultIndex')); - const defaultIndexPattern = indexPattern.attributes.title; - this.props.vis.params.index_pattern = defaultIndexPattern; - } + const savedObjectsClient = chrome.getSavedObjectsClient(); + const indexPattern = await savedObjectsClient.get('index-pattern', this.getConfig('defaultIndex')); + + this.handleChange({ + default_index_pattern: indexPattern.attributes.title + }); } handleChange = async (partialModel) => { diff --git a/src/legacy/core_plugins/metrics/public/components/vis_types/table/series.js b/src/legacy/core_plugins/metrics/public/components/vis_types/table/series.js index f65c15965fc21..ce1e33e07d48d 100644 --- a/src/legacy/core_plugins/metrics/public/components/vis_types/table/series.js +++ b/src/legacy/core_plugins/metrics/public/components/vis_types/table/series.js @@ -28,7 +28,7 @@ import createAggRowRender from '../../lib/create_agg_row_render'; import { createUpDownHandler } from '../../lib/sort_keyhandler'; import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; -function TopNSeries(props) { +function TableSeries(props) { const { model, onAdd, @@ -177,7 +177,7 @@ function TopNSeries(props) { ); } -TopNSeries.propTypes = { +TableSeries.propTypes = { className: PropTypes.string, disableAdd: PropTypes.bool, disableDelete: PropTypes.bool, @@ -201,4 +201,4 @@ TopNSeries.propTypes = { visible: PropTypes.bool }; -export default injectI18n(TopNSeries); +export default injectI18n(TableSeries); diff --git a/src/legacy/core_plugins/metrics/public/components/vis_types/table/vis.js b/src/legacy/core_plugins/metrics/public/components/vis_types/table/vis.js index 48db04c2996e7..59e9219712502 100644 --- a/src/legacy/core_plugins/metrics/public/components/vis_types/table/vis.js +++ b/src/legacy/core_plugins/metrics/public/components/vis_types/table/vis.js @@ -41,6 +41,12 @@ function getColor(rules, colorKey, value) { return color; } +const getPercentileLabel = (metric, item) => { + const { value } = _.last(metric.percentiles); + const label = calculateLabel(metric, item.metrics); + return `${label}, ${value || 0}`; +}; + class TableVis extends Component { constructor(props) { @@ -95,7 +101,9 @@ class TableVis extends Component { }); const columns = model.series.map(item => { const metric = _.last(item.metrics); - const label = item.label || calculateLabel(metric, item.metrics); + const label = metric.type === 'percentile' ? + getPercentileLabel(metric, item) : + item.label || calculateLabel(metric, item.metrics); const handleClick = () => { if (!isSortable(metric)) return; let order; diff --git a/src/legacy/core_plugins/metrics/public/components/vis_types/timeseries/config.js b/src/legacy/core_plugins/metrics/public/components/vis_types/timeseries/config.js index a63f55734ea16..92787b189a94a 100644 --- a/src/legacy/core_plugins/metrics/public/components/vis_types/timeseries/config.js +++ b/src/legacy/core_plugins/metrics/public/components/vis_types/timeseries/config.js @@ -62,6 +62,13 @@ const TimeseriesConfig = injectI18n(function (props) { const stackedOptions = [ { label: intl.formatMessage({ id: 'tsvb.timeSeries.noneLabel', defaultMessage: 'None' }), value: 'none' }, { label: intl.formatMessage({ id: 'tsvb.timeSeries.stackedLabel', defaultMessage: 'Stacked' }), value: 'stacked' }, + { + label: intl.formatMessage({ + id: 'tsvb.timeSeries.stackedWithinSeriesLabel', + defaultMessage: 'Stacked within series' + }), + value: 'stacked_within_series' + }, { label: intl.formatMessage({ id: 'tsvb.timeSeries.percentLabel', defaultMessage: 'Percent' }), value: 'percent' } ]; const selectedStackedOption = stackedOptions.find(option => { diff --git a/src/legacy/core_plugins/metrics/public/components/visualization.js b/src/legacy/core_plugins/metrics/public/components/visualization.js index 1af0f8eb85a9e..6e1fcea29016d 100644 --- a/src/legacy/core_plugins/metrics/public/components/visualization.js +++ b/src/legacy/core_plugins/metrics/public/components/visualization.js @@ -27,7 +27,7 @@ import topN from './vis_types/top_n/vis'; import table from './vis_types/table/vis'; import gauge from './vis_types/gauge/vis'; import markdown from './vis_types/markdown/vis'; -import Error from './error'; +import ErrorComponent from './error'; import NoData from './no_data'; const types = { @@ -46,7 +46,7 @@ function Visualization(props) { if (error) { return (
- +
); } diff --git a/src/legacy/core_plugins/metrics/server/lib/get_fields.js b/src/legacy/core_plugins/metrics/server/lib/get_fields.js index c9588d057614d..3902e6dacb1bc 100644 --- a/src/legacy/core_plugins/metrics/server/lib/get_fields.js +++ b/src/legacy/core_plugins/metrics/server/lib/get_fields.js @@ -16,13 +16,18 @@ * specific language governing permissions and limitations * under the License. */ - +import { SearchStrategiesRegister } from './search_strategies/search_strategies_register'; import { uniq } from 'lodash'; +import { getIndexPatternObject } from './vis_data/helpers/get_index_pattern'; export async function getFields(req) { - const { indexPatternsService } = req.pre; - const index = req.query.index || '*'; - const resp = await indexPatternsService.getFieldsForWildcard({ pattern: index }); - const fields = resp.filter(field => field.aggregatable); + const indexPattern = req.query.index; + const { indexPatternString } = await getIndexPatternObject(req, indexPattern); + const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy(req, indexPatternString); + + const fields = (await searchStrategy + .getFieldsForWildcard(req, indexPatternString, capabilities)) + .filter(field => field.aggregatable); + return uniq(fields, field => field.name); } diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/default_search_capabilities.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/default_search_capabilities.js new file mode 100644 index 0000000000000..33e268577bf04 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/default_search_capabilities.js @@ -0,0 +1,58 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { convertIntervalToUnit, parseInterval } from '../vis_data/helpers/unit_to_seconds'; + +const getTimezoneFromRequest = request => { + return request.payload.timerange.timezone; +}; + +export class DefaultSearchCapabilities { + constructor(request, batchRequestsSupport, fieldsCapabilities = {}) { + this.request = request; + this.batchRequestsSupport = batchRequestsSupport; + this.fieldsCapabilities = fieldsCapabilities; + } + + get defaultTimeInterval() { + return null; + } + + get searchTimezone() { + return getTimezoneFromRequest(this.request); + } + + parseInterval(interval) { + return parseInterval(interval); + } + + convertIntervalToUnit(intervalString, unit) { + const parsedInterval = this.parseInterval(intervalString); + + if (parsedInterval.unit !== unit) { + return convertIntervalToUnit(intervalString, unit); + } + + return parsedInterval; + } + + getValidTimeInterval(intervalString) { + // Default search capabilities doesn't have any restrictions for the interval string + return intervalString; + } +} diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/default_search_capabilities.test.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/default_search_capabilities.test.js new file mode 100644 index 0000000000000..5d41e03722d9d --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/default_search_capabilities.test.js @@ -0,0 +1,106 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { DefaultSearchCapabilities } from './default_search_capabilities'; + +describe('DefaultSearchCapabilities', () => { + let defaultSearchCapabilities; + let batchRequestsSupport; + let req; + + beforeEach(() => { + req = {}; + batchRequestsSupport = true; + defaultSearchCapabilities = new DefaultSearchCapabilities(req, batchRequestsSupport); + }); + + test('should init default search capabilities', () => { + expect(defaultSearchCapabilities.request).toBe(req); + expect(defaultSearchCapabilities.batchRequestsSupport).toBe(batchRequestsSupport); + expect(defaultSearchCapabilities.fieldsCapabilities).toEqual({}); + }); + + test('should return defaultTimeInterval', () => { + expect(defaultSearchCapabilities.defaultTimeInterval).toBe(null); + }); + + test('should return Search Timezone', () => { + defaultSearchCapabilities.request = { + payload: { + timerange: { + timezone: 'UTC' + } + } + }; + + expect(defaultSearchCapabilities.searchTimezone).toEqual('UTC'); + }); + + test('should return a valid time interval', () => { + expect(defaultSearchCapabilities.getValidTimeInterval('20m')).toBe('20m'); + }); + + test('should parse interval', () => { + expect(defaultSearchCapabilities.parseInterval('120s')).toEqual({ + value: 120, + unit: 's' + }); + + expect(defaultSearchCapabilities.parseInterval('20m')).toEqual({ + value: 20, + unit: 'm' + }); + + expect(defaultSearchCapabilities.parseInterval('1y')).toEqual({ + value: 1, + unit: 'y' + }); + }); + + test('should convert interval string into different unit', () => { + expect(defaultSearchCapabilities.convertIntervalToUnit('120s', 's')).toEqual({ + value: 120, + unit: 's' + }); + + expect(defaultSearchCapabilities.convertIntervalToUnit('60m', 'h')).toEqual({ + value: 1, + unit: 'h' + }); + + expect(defaultSearchCapabilities.convertIntervalToUnit('4w', 'M')).toEqual({ + value: 1, + unit: 'M' + }); + + expect(defaultSearchCapabilities.convertIntervalToUnit('1y', 'w')).toEqual({ + value: 48, + unit: 'w' + }); + + expect(defaultSearchCapabilities.convertIntervalToUnit('60s', 'm')).toEqual({ + value: 1, + unit: 'm' + }); + + expect(defaultSearchCapabilities.convertIntervalToUnit('1s', 'ms')).toEqual({ + value: 1000, + unit: 'ms' + }); + }); +}); diff --git a/test/functional/services/lib/leadfoot_element_wrapper/index.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/index.js similarity index 91% rename from test/functional/services/lib/leadfoot_element_wrapper/index.js rename to src/legacy/core_plugins/metrics/server/lib/search_strategies/index.js index 8569f9a2e120c..512894f30a619 100644 --- a/test/functional/services/lib/leadfoot_element_wrapper/index.js +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/index.js @@ -17,4 +17,4 @@ * under the License. */ -export { LeadfootElementWrapper } from './leadfoot_element_wrapper'; +export { SearchStrategiesRegister } from './search_strategies_register'; diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/search_strategies_register.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/search_strategies_register.js new file mode 100644 index 0000000000000..159e25191fc94 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/search_strategies_register.js @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { AbstractSearchStrategy } from './strategies/abstract_search_strategy'; +import { AbstractSearchRequest } from './searh_requests/abstract_request'; +import { DefaultSearchStrategy } from './strategies/default_search_strategy'; +import { DefaultSearchCapabilities } from './default_search_capabilities'; + +const strategies = []; + +const addStrategy = searchStrategy => { + if (searchStrategy instanceof AbstractSearchStrategy) { + strategies.unshift(searchStrategy); + } + return strategies; +}; + +export class SearchStrategiesRegister { + static init(server) { + server.expose('AbstractSearchStrategy', AbstractSearchStrategy); + server.expose('AbstractSearchRequest', AbstractSearchRequest); + server.expose('DefaultSearchCapabilities', DefaultSearchCapabilities); + server.expose('addSearchStrategy', searchStrategy => addStrategy(searchStrategy)); + + addStrategy(new DefaultSearchStrategy(server)); + } + + static async getViableStrategy(req, indexPattern) { + for (const searchStrategy of strategies) { + const { isViable, capabilities } = await searchStrategy.checkForViability(req, indexPattern); + + if (isViable) { + return { + searchStrategy, + capabilities, + }; + } + } + } +} diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/search_strategies_register.test.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/search_strategies_register.test.js new file mode 100644 index 0000000000000..abe25b4737b7e --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/search_strategies_register.test.js @@ -0,0 +1,94 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { SearchStrategiesRegister } from './search_strategies_register'; +import { AbstractSearchStrategy } from './strategies/abstract_search_strategy'; +import { DefaultSearchStrategy } from './strategies/default_search_strategy'; +import { AbstractSearchRequest } from './searh_requests/abstract_request'; +import { DefaultSearchCapabilities } from './default_search_capabilities'; + +class MockSearchStrategy extends AbstractSearchStrategy { + checkForViability() { + return { + isViable: true, + capabilities: {} + }; + } +} + +describe('SearchStrategiesRegister', () => { + let server; + let strategies; + let anotherSearchStrategy; + + beforeAll(() => { + server = { + expose: jest.fn((strategy, func) => { + server[strategy] = func; + }) + }; + strategies = [ + ['AbstractSearchStrategy', AbstractSearchStrategy], + ['AbstractSearchRequest', AbstractSearchRequest], + ['DefaultSearchCapabilities', DefaultSearchCapabilities], + ['addSearchStrategy', expect.any(Function)] + ]; + + SearchStrategiesRegister.init(server); + }); + + test('should init strategies register', () => { + expect(server.expose.mock.calls).toEqual(strategies); + expect(server.addSearchStrategy()[0] instanceof DefaultSearchStrategy).toBe(true); + }); + + test('should not add a strategy if it is not an instance of AbstractSearchStrategy', () => { + const addedStrategies = server.addSearchStrategy({}); + + expect(addedStrategies.length).toEqual(1); + expect(addedStrategies[0] instanceof DefaultSearchStrategy).toBe(true); + }); + + test('should return a DefaultSearchStrategy instance', async () => { + const req = {}; + const indexPattern = '*'; + + const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy(req, indexPattern); + + expect(searchStrategy instanceof DefaultSearchStrategy).toBe(true); + expect(capabilities instanceof DefaultSearchCapabilities).toBe(true); + }); + + test('should add a strategy if it is an instance of AbstractSearchStrategy', () => { + anotherSearchStrategy = new MockSearchStrategy(); + const addedStrategies = server.addSearchStrategy(anotherSearchStrategy); + + expect(addedStrategies.length).toEqual(2); + expect(addedStrategies[0] instanceof AbstractSearchStrategy).toBe(true); + }); + + test('should return a MockSearchStrategy instance', async () => { + const req = {}; + const indexPattern = '*'; + + const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy(req, indexPattern); + + expect(searchStrategy instanceof AbstractSearchStrategy).toBe(true); + expect(capabilities).toEqual({}); + }); +}); diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/abstract_request.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/abstract_request.js new file mode 100644 index 0000000000000..cfacaf18a5abf --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/abstract_request.js @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 class AbstractSearchRequest { + constructor(req, callWithRequest, indexPattern) { + this.req = req; + this.callWithRequest = callWithRequest; + this.indexPattern = indexPattern; + } + + search() { + throw new Error('AbstractSearchRequest: search method should be defined'); + } +} diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/abstract_request.test.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/abstract_request.test.js new file mode 100644 index 0000000000000..16dbd9b580f69 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/abstract_request.test.js @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { AbstractSearchRequest } from './abstract_request'; + +describe('AbstractSearchRequest', () => { + let searchRequest; + let req; + let callWithRequest; + let indexPattern; + + beforeEach(() => { + req = {}; + callWithRequest = jest.fn(); + indexPattern = 'indexPattern'; + searchRequest = new AbstractSearchRequest(req, callWithRequest, indexPattern); + }); + + test('should init an AbstractSearchRequest instance', () => { + expect(searchRequest.req).toBe(req); + expect(searchRequest.callWithRequest).toBe(callWithRequest); + expect(searchRequest.indexPattern).toBe(indexPattern); + expect(searchRequest.search).toBeDefined(); + }); + + test('should throw an error trying to search', () => { + try { + searchRequest.search(); + } catch (error) { + expect(error instanceof Error).toBe(true); + expect(error.message).toEqual('AbstractSearchRequest: search method should be defined'); + } + }); +}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/create_admin_cluster.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/multi_search_request.js similarity index 62% rename from src/legacy/core_plugins/elasticsearch/lib/create_admin_cluster.js rename to src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/multi_search_request.js index c3a46c2b15735..793448073397b 100644 --- a/src/legacy/core_plugins/elasticsearch/lib/create_admin_cluster.js +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/multi_search_request.js @@ -16,23 +16,19 @@ * specific language governing permissions and limitations * under the License. */ +import { AbstractSearchRequest } from './abstract_request'; -import { clientLogger } from './client_logger'; +const SEARCH_METHOD = 'msearch'; -export function createAdminCluster(server) { - const config = server.config(); - const ElasticsearchClientLogging = clientLogger(server); +export class MultiSearchRequest extends AbstractSearchRequest { + async search(options) { + const includeFrozen = await this.req.getUiSettingsService().get('search:includeFrozen'); + const { responses } = await this.callWithRequest(this.req, SEARCH_METHOD, { + ...options, + rest_total_hits_as_int: true, + ignore_throttled: !includeFrozen, + }); - class AdminClientLogging extends ElasticsearchClientLogging { - tags = ['admin']; - logQueries = config.get('elasticsearch.logQueries'); + return responses; } - - server.plugins.elasticsearch.createCluster( - 'admin', - { - log: AdminClientLogging, - ...config.get('elasticsearch') - } - ); } diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/multi_search_request.test.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/multi_search_request.test.js new file mode 100644 index 0000000000000..48d24f7622796 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/multi_search_request.test.js @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { MultiSearchRequest } from './multi_search_request'; + +describe('MultiSearchRequest', () => { + let searchRequest; + let req; + let callWithRequest; + let indexPattern; + let getServiceMock; + let includeFrozen; + + beforeEach(() => { + includeFrozen = false; + getServiceMock = jest.fn().mockResolvedValue(includeFrozen); + req = { + getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }) + }; + callWithRequest = jest.fn().mockReturnValue({ responses: [] }); + indexPattern = 'indexPattern'; + searchRequest = new MultiSearchRequest(req, callWithRequest, indexPattern); + }); + + test('should init an MultiSearchRequest instance', () => { + expect(searchRequest.req).toBe(req); + expect(searchRequest.callWithRequest).toBe(callWithRequest); + expect(searchRequest.indexPattern).toBe(indexPattern); + expect(searchRequest.search).toBeDefined(); + }); + + test('should get the response from elastic msearch', async () => { + const options = {}; + + const responses = await searchRequest.search(options); + + expect(responses).toEqual([]); + expect(req.getUiSettingsService).toHaveBeenCalled(); + expect(getServiceMock).toHaveBeenCalledWith('search:includeFrozen'); + expect(callWithRequest).toHaveBeenCalledWith(req, 'msearch', { + ...options, + rest_total_hits_as_int: true, + ignore_throttled: !includeFrozen, + }); + }); +}); diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/search_request.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/search_request.js new file mode 100644 index 0000000000000..afab9d37f3018 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/search_request.js @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { AbstractSearchRequest } from './abstract_request'; + +import { MultiSearchRequest } from './multi_search_request'; +import { SingleSearchRequest } from './single_search_request'; + +export class SearchRequest extends AbstractSearchRequest { + getSearchRequestType(options) { + const isMultiSearch = Array.isArray(options.body); + const SearchRequest = isMultiSearch ? MultiSearchRequest : SingleSearchRequest; + + return new SearchRequest(this.req, this.callWithRequest, this.indexPattern); + } + + async search(options) { + const concreteSearchRequest = this.getSearchRequestType(options); + + return concreteSearchRequest.search(options); + } +} diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/search_request.test.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/search_request.test.js new file mode 100644 index 0000000000000..608f8abddf95d --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/search_request.test.js @@ -0,0 +1,78 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { SearchRequest } from './search_request'; +import { MultiSearchRequest } from './multi_search_request'; +import { SingleSearchRequest } from './single_search_request'; + +describe('SearchRequest', () => { + let searchRequest; + let req; + let callWithRequest; + let indexPattern; + let getServiceMock; + let includeFrozen; + + beforeEach(() => { + includeFrozen = false; + getServiceMock = jest.fn().mockResolvedValue(includeFrozen); + req = { + getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }) + }; + callWithRequest = jest.fn().mockReturnValue({ responses: [] }); + indexPattern = 'indexPattern'; + searchRequest = new SearchRequest(req, callWithRequest, indexPattern); + }); + + test('should init an AbstractSearchRequest instance', () => { + expect(searchRequest.req).toBe(req); + expect(searchRequest.callWithRequest).toBe(callWithRequest); + expect(searchRequest.indexPattern).toBe(indexPattern); + expect(searchRequest.search).toBeDefined(); + }); + + test('should return search value', async () => { + const concreteSearchRequest = { + search: jest.fn().mockReturnValue('concreteSearchRequest') + }; + const options = {}; + searchRequest.getSearchRequestType = jest.fn().mockReturnValue(concreteSearchRequest); + + const result = await searchRequest.search(options); + + expect(result).toBe('concreteSearchRequest'); + }); + + test('should return a MultiSearchRequest if options has body as an array', () => { + const options = { + body: [] + }; + + const result = searchRequest.getSearchRequestType(options); + + expect(result instanceof MultiSearchRequest).toBe(true); + }); + + test('should return a SingleSearchRequest if options has body', () => { + const options = {}; + + const result = searchRequest.getSearchRequestType(options); + + expect(result instanceof SingleSearchRequest).toBe(true); + }); +}); diff --git a/src/legacy/core_plugins/elasticsearch/lib/create_agent.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/single_search_request.js similarity index 63% rename from src/legacy/core_plugins/elasticsearch/lib/create_agent.js rename to src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/single_search_request.js index f636c9edcc1b8..df27b890f0fd0 100644 --- a/src/legacy/core_plugins/elasticsearch/lib/create_agent.js +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/single_search_request.js @@ -16,19 +16,19 @@ * specific language governing permissions and limitations * under the License. */ +import { AbstractSearchRequest } from './abstract_request'; -import url from 'url'; -import { get } from 'lodash'; -import http from 'http'; -import https from 'https'; +const SEARCH_METHOD = 'search'; -import { parseConfig } from './parse_config'; +export class SingleSearchRequest extends AbstractSearchRequest { + async search(options) { + const includeFrozen = await this.req.getUiSettingsService().get('search:includeFrozen'); + const resp = await this.callWithRequest(this.req, SEARCH_METHOD, { + ...options, + index: this.indexPattern, + ignore_throttled: !includeFrozen, + }); -export default function (config) { - const target = url.parse(get(config, 'url')); - - if (!/^https/.test(target.protocol)) return new http.Agent(); - - const ignoreCertAndKey = !get(config, 'ssl.alwaysPresentCertificate'); - return new https.Agent(parseConfig(config, { ignoreCertAndKey }).ssl); + return [resp]; + } } diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/single_search_request.test.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/single_search_request.test.js new file mode 100644 index 0000000000000..97cbaa188cee4 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/searh_requests/single_search_request.test.js @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { SingleSearchRequest } from './single_search_request'; + +describe('SingleSearchRequest', () => { + let searchRequest; + let req; + let callWithRequest; + let indexPattern; + let getServiceMock; + let includeFrozen; + + beforeEach(() => { + includeFrozen = false; + getServiceMock = jest.fn().mockResolvedValue(includeFrozen); + req = { + getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }) + }; + callWithRequest = jest.fn().mockReturnValue({}); + indexPattern = 'indexPattern'; + searchRequest = new SingleSearchRequest(req, callWithRequest, indexPattern); + }); + + test('should init an SingleSearchRequest instance', () => { + expect(searchRequest.req).toBe(req); + expect(searchRequest.callWithRequest).toBe(callWithRequest); + expect(searchRequest.indexPattern).toBe(indexPattern); + expect(searchRequest.search).toBeDefined(); + }); + + test('should get the response from elastic search', async () => { + const options = {}; + + const responses = await searchRequest.search(options); + + expect(responses).toEqual([{}]); + expect(req.getUiSettingsService).toHaveBeenCalled(); + expect(getServiceMock).toHaveBeenCalledWith('search:includeFrozen'); + expect(callWithRequest).toHaveBeenCalledWith(req, 'search', { + ...options, + index: indexPattern, + ignore_throttled: !includeFrozen, + }); + }); +}); diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/abstract_search_strategy.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/abstract_search_strategy.js new file mode 100644 index 0000000000000..2df4652e8179c --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/abstract_search_strategy.js @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 class AbstractSearchStrategy { + constructor(server, callWithRequestFactory, SearchRequest) { + this.getCallWithRequestInstance = req => callWithRequestFactory(server, req); + + this.getSearchRequest = (req, indexPattern) => { + const callWithRequest = this.getCallWithRequestInstance(req); + + return new SearchRequest(req, callWithRequest, indexPattern); + }; + } + + async getFieldsForWildcard(req, indexPattern) { + const { indexPatternsService } = req.pre; + + return await indexPatternsService.getFieldsForWildcard({ + pattern: indexPattern, + }); + } + + checkForViability() { + throw new TypeError('Must override method'); + } +} diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/abstract_search_strategy.test.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/abstract_search_strategy.test.js new file mode 100644 index 0000000000000..c063c5047d069 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/abstract_search_strategy.test.js @@ -0,0 +1,83 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { AbstractSearchStrategy } from './abstract_search_strategy'; + +class SearchRequest { + constructor(req, callWithRequest, indexPattern) { + this.req = req; + this.callWithRequest = callWithRequest; + this.indexPattern = indexPattern; + } +} + +describe('AbstractSearchStrategy', () => { + let abstractSearchStrategy; + let server; + let callWithRequestFactory; + let req; + let mockedFields; + let indexPattern; + + beforeEach(() => { + server = {}; + callWithRequestFactory = jest.fn().mockReturnValue('callWithRequest'); + mockedFields = {}; + indexPattern = '*'; + req = { + pre: { + indexPatternsService: { + getFieldsForWildcard: jest.fn().mockReturnValue(mockedFields) + } + } + }; + + abstractSearchStrategy = new AbstractSearchStrategy(server, callWithRequestFactory, SearchRequest); + }); + + test('should init an AbstractSearchStrategy instance', () => { + expect(abstractSearchStrategy.getCallWithRequestInstance).toBeDefined(); + expect(abstractSearchStrategy.getSearchRequest).toBeDefined(); + expect(abstractSearchStrategy.getFieldsForWildcard).toBeDefined(); + expect(abstractSearchStrategy.checkForViability).toBeDefined(); + }); + + test('should return fields for wildcard', async () => { + const fields = await abstractSearchStrategy.getFieldsForWildcard(req, indexPattern); + + expect(fields).toBe(mockedFields); + expect(req.pre.indexPatternsService.getFieldsForWildcard).toHaveBeenCalledWith({ + pattern: indexPattern, + }); + }); + + test('should invoke callWithRequestFactory with req param passed', () => { + abstractSearchStrategy.getCallWithRequestInstance(req); + + expect(callWithRequestFactory).toHaveBeenCalledWith(server, req); + }); + + test('should return a search request', () => { + const searchRequest = abstractSearchStrategy.getSearchRequest(req, indexPattern); + + expect(searchRequest instanceof SearchRequest).toBe(true); + expect(searchRequest.indexPattern).toBe(indexPattern); + expect(searchRequest.callWithRequest).toBe('callWithRequest'); + expect(searchRequest.req).toBe(req); + }); +}); diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/default_search_strategy.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/default_search_strategy.js new file mode 100644 index 0000000000000..15a796b5e511a --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/default_search_strategy.js @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { AbstractSearchStrategy } from './abstract_search_strategy'; +import { SearchRequest } from '../searh_requests/search_request'; +import { DefaultSearchCapabilities } from '../default_search_capabilities'; + +const callWithRequestFactory = (server, request) => { + const { callWithRequest } = request.server.plugins.elasticsearch.getCluster('data'); + + return callWithRequest; +}; +const batchRequestsSupport = true; + +export class DefaultSearchStrategy extends AbstractSearchStrategy { + name = 'default'; + + constructor(server) { + super(server, callWithRequestFactory, SearchRequest); + } + + checkForViability(req) { + return { + isViable: true, + capabilities: new DefaultSearchCapabilities(req, batchRequestsSupport) + }; + } +} diff --git a/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/default_search_strategy.test.js b/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/default_search_strategy.test.js new file mode 100644 index 0000000000000..9f1750c1b3db2 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/search_strategies/strategies/default_search_strategy.test.js @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { DefaultSearchStrategy } from './default_search_strategy'; + +describe('DefaultSearchStrategy', () => { + let defaultSearchStrategy; + let server; + let callWithRequest; + let req; + + beforeEach(() => { + server = {}; + callWithRequest = jest.fn(); + req = { + server: { + plugins: { + elasticsearch: { + getCluster: jest.fn().mockReturnValue({ + callWithRequest + }) + } + } + } + }; + defaultSearchStrategy = new DefaultSearchStrategy(server); + }); + + test('should init an DefaultSearchStrategy instance', () => { + expect(defaultSearchStrategy.name).toBe('default'); + expect(defaultSearchStrategy.checkForViability).toBeDefined(); + expect(defaultSearchStrategy.getCallWithRequestInstance).toBeDefined(); + expect(defaultSearchStrategy.getSearchRequest).toBeDefined(); + expect(defaultSearchStrategy.getFieldsForWildcard).toBeDefined(); + }); + + test('should invoke callWithRequestFactory with passed params', () => { + const value = defaultSearchStrategy.getCallWithRequestInstance(req); + + expect(value).toBe(callWithRequest); + expect(req.server.plugins.elasticsearch.getCluster).toHaveBeenCalledWith('data'); + }); + + test('should check a strategy for viability', () => { + const value = defaultSearchStrategy.checkForViability(req); + + expect(value.isViable).toBe(true); + expect(value.capabilities).toEqual({ + request: req, + batchRequestsSupport: true, + fieldsCapabilities: {}, + }); + }); +}); diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_agg_value.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_agg_value.js index 804d50464b47a..8b6d194c92aad 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_agg_value.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_agg_value.js @@ -131,6 +131,15 @@ describe('getAggValue', () => { }, }; + + describe('count', () => { + testAgg( + basicWithDerv, + { id: 'test', type: 'count' }, + 2 + ); + }); + describe('derivative', () => { testAgg( basicWithDerv, diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_default_decoration.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_default_decoration.js index df38d83d84eca..210db17f85fb5 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_default_decoration.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_default_decoration.js @@ -22,6 +22,45 @@ import getDefaultDecoration from '../../helpers/get_default_decoration'; describe('getDefaultDecoration', () => { + describe('stack option', () => { + + it('should set a stack option to false', () => { + const series = { + id: 'test_id' + }; + expect(getDefaultDecoration(series)) + .to.have.property('stack', false); + + series.stacked = 'none'; + expect(getDefaultDecoration(series)) + .to.have.property('stack', false); + }); + + it('should set a stack option to true', () => { + const series = { + stacked: 'stacked', + id: 'test_id' + }; + + expect(getDefaultDecoration(series)) + .to.have.property('stack', true); + + series.stacked = 'percent'; + expect(getDefaultDecoration(series)) + .to.have.property('stack', true); + }); + + it('should set a stack option to be series id', () => { + const series = { + stacked: 'stacked_within_series', + id: 'test_id' + }; + + expect(getDefaultDecoration(series)) + .to.have.property('stack', series.id); + }); + }); + describe('lines', () => { it('return decoration for lines', () => { const series = { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_es_shard_timeout.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_es_shard_timeout.js index aa4a15b820247..b10005c35368d 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_es_shard_timeout.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_es_shard_timeout.js @@ -17,23 +17,23 @@ * under the License. */ -import sinon from 'sinon'; +import moment from 'moment'; +import { of } from 'rxjs'; import { expect } from 'chai'; -import getEsShardTimeout from '../../helpers/get_es_shard_timeout'; +import { getEsShardTimeout } from '../../helpers/get_es_shard_timeout'; describe('getEsShardTimeout', () => { - it('should return the elasticsearch.shardTimeout', () => { - const getConfig = sinon.spy(() => '30000'); + it('should return the elasticsearch.shardTimeout', async () => { const req = { server: { - config: () => ({ - get: getConfig - }) + core: { + elasticsearch: { legacy: { config$: of({ shardTimeout: moment.duration(12345) }) } } + } } }; - const timeout = getEsShardTimeout(req); - expect(timeout).to.equal('30000'); - expect(getConfig.called).to.equal(true); + const timeout = await getEsShardTimeout(req); + + expect(timeout).to.equal(12345); }); }); diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/annorations/build_request_body.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/annorations/build_request_body.js new file mode 100644 index 0000000000000..91f55b1eb2200 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/annorations/build_request_body.js @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 buildProcessorFunction from '../build_processor_function'; +import processors from '../request_processors/annotations'; + +/** + * Builds annotation request body + * + * @param {...args}: [ + * req: {Object} - a request object, + * panel: {Object} - a panel object, + * annotation: {Object} - an annotation object, + * esQueryConfig: {Object} - es query config object, + * indexPatternObject: {Object} - an index pattern object, + * capabilities: {Object} - a search capabilities object + * ] + * @returns {Object} doc - processed body + */ +export function buildAnnotationRequest(...args) { + const processor = buildProcessorFunction(processors, ...args); + const doc = processor({}); + return doc; +} diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/annorations/get_request_params.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/annorations/get_request_params.js new file mode 100644 index 0000000000000..4a97fb658ca21 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/annorations/get_request_params.js @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { buildAnnotationRequest } from './build_request_body'; +import { getEsShardTimeout } from '../helpers/get_es_shard_timeout'; +import { getIndexPatternObject } from '../helpers/get_index_pattern'; + +export async function getAnnotationRequestParams(req, panel, annotation, esQueryConfig, capabilities) { + const bodies = []; + const esShardTimeout = await getEsShardTimeout(req); + const indexPattern = annotation.index_pattern; + const { indexPatternObject, indexPatternString } = await getIndexPatternObject(req, indexPattern); + const request = buildAnnotationRequest(req, panel, annotation, esQueryConfig, indexPatternObject, capabilities); + + if (capabilities.batchRequestsSupport) { + bodies.push({ + index: indexPatternString, + ignoreUnavailable: true, + }); + } + + if (esShardTimeout > 0) { + request.timeout = `${esShardTimeout}ms`; + } + + bodies.push(request); + + return bodies; +} diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/get_annotations.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/get_annotations.js index af37c3f3dab7d..3a71358b92ddb 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/get_annotations.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/get_annotations.js @@ -16,11 +16,8 @@ * specific language governing permissions and limitations * under the License. */ - -import buildAnnotationRequest from './build_annotation_request'; import handleAnnotationResponse from './handle_annotation_response'; -import { getIndexPatternObject } from './helpers/get_index_pattern'; -import getEsShardTimeout from './helpers/get_es_shard_timeout'; +import { getAnnotationRequestParams } from './annorations/get_request_params'; function validAnnotation(annotation) { return annotation.index_pattern && @@ -30,55 +27,28 @@ function validAnnotation(annotation) { annotation.template; } -export default async (req, panel, esQueryConfig) => { - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('data'); - const bodiesPromises = panel.annotations - .filter(validAnnotation) - .map(annotation => { - return getAnnotationBody(req, panel, annotation, esQueryConfig); - }); - const bodies = await Promise.all(bodiesPromises); - if (!bodies.length) { - return { - responses: [], - }; - } +export async function getAnnotations(req, panel, esQueryConfig, searchStrategy, capabilities) { + const panelIndexPattern = panel.index_pattern; + const searchRequest = searchStrategy.getSearchRequest(req, panelIndexPattern); + const annotations = panel.annotations.filter(validAnnotation); + + const bodiesPromises = annotations.map(annotation => getAnnotationRequestParams(req, panel, annotation, esQueryConfig, capabilities)); + const body = (await Promise.all(bodiesPromises)) + .reduce((acc, items) => acc.concat(items), []); + + if (!body.length) return { responses: [] }; + try { - const includeFrozen = await req.getUiSettingsService().get('search:includeFrozen'); - const resp = await callWithRequest(req, 'msearch', { - ignore_throttled: !includeFrozen, - rest_total_hits_as_int: true, - body: bodies.reduce((acc, item) => acc.concat(item), []) - }); - const results = {}; - panel.annotations - .filter(validAnnotation) - .forEach((annotation, index) => { - const data = resp.responses[index]; - results[annotation.id] = handleAnnotationResponse(data, annotation); - }); - return results; + const responses = await searchRequest.search({ body }); + + return annotations + .reduce((acc, annotation, index) => { + acc[annotation.id] = handleAnnotationResponse(responses[index], annotation); + + return acc; + }, {}); } catch (error) { if (error.message === 'missing-indices') return { responses: [] }; throw error; } -}; - -async function getAnnotationBody(req, panel, annotation, esQueryConfig) { - const indexPattern = annotation.index_pattern; - const { indexPatternObject, indexPatternString } = await getIndexPatternObject(req, indexPattern); - const request = buildAnnotationRequest(req, panel, annotation, esQueryConfig, indexPatternObject); - const esShardTimeout = getEsShardTimeout(req); - - if (esShardTimeout > 0) { - request.timeout = `${esShardTimeout}ms`; - } - - return [ - { - index: indexPatternString, - ignoreUnavailable: true, - }, - request, - ]; } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/get_series_data.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/get_series_data.js index 2594db2c5db6d..b6624b8fcc5ea 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/get_series_data.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/get_series_data.js @@ -16,50 +16,44 @@ * specific language governing permissions and limitations * under the License. */ - -import getRequestParams from './series/get_request_params'; +import { getSeriesRequestParams } from './series/get_request_params'; import handleResponseBody from './series/handle_response_body'; import handleErrorResponse from './handle_error_response'; -import getAnnotations from './get_annotations'; +import { getAnnotations } from './get_annotations'; +import { SearchStrategiesRegister } from '../search_strategies/search_strategies_register'; import { getEsQueryConfig } from './helpers/get_es_query_uisettings'; export async function getSeriesData(req, panel) { - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('data'); - const includeFrozen = await req.getUiSettingsService().get('search:includeFrozen'); + const panelIndexPattern = panel.index_pattern; + const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy(req, panelIndexPattern); + const searchRequest = searchStrategy.getSearchRequest(req, panelIndexPattern); const esQueryConfig = await getEsQueryConfig(req); - try { - const bodiesPromises = panel.series.map(series => getRequestParams(req, panel, series, esQueryConfig)); - const bodies = await Promise.all(bodiesPromises); - const params = { - rest_total_hits_as_int: true, - ignore_throttled: !includeFrozen, - body: bodies.reduce((acc, items) => acc.concat(items), []) - }; - return callWithRequest(req, 'msearch', params) - .then(resp => { - const series = resp.responses.map(handleResponseBody(panel)); - return { - [panel.id]: { - id: panel.id, - series: series.reduce((acc, series) => acc.concat(series), []) - } - }; - }) - .then(resp => { - if (!panel.annotations || panel.annotations.length === 0) return resp; - return getAnnotations(req, panel, esQueryConfig).then(annotations => { - resp[panel.id].annotations = annotations; - return resp; - }); - }) - .then(resp => { - resp.type = panel.type; + const bodiesPromises = panel.series.map(series => getSeriesRequestParams(req, panel, series, esQueryConfig, capabilities)); + const body = (await Promise.all(bodiesPromises)) + .reduce((acc, items) => acc.concat(items), []); + + return searchRequest.search({ body }) + .then(data => { + const series = data.map(handleResponseBody(panel)); + return { + [panel.id]: { + id: panel.id, + series: series.reduce((acc, series) => acc.concat(series), []), + }, + }; + }) + .then(resp => { + if (!panel.annotations || panel.annotations.length === 0) return resp; + return getAnnotations(req, panel, esQueryConfig, searchStrategy, capabilities).then(annotations => { + resp[panel.id].annotations = annotations; return resp; - }) - .catch(handleErrorResponse(panel)); - } catch(e) { - return handleErrorResponse(e); - } + }); + }) + .then(resp => { + resp.type = panel.type; + return resp; + }) + .catch(handleErrorResponse(panel)); } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/get_table_data.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/get_table_data.js index 53c18a9c6a1ae..c552022473e00 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/get_table_data.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/get_table_data.js @@ -16,29 +16,25 @@ * specific language governing permissions and limitations * under the License. */ -import { get } from 'lodash'; + import buildRequestBody from './table/build_request_body'; import handleErrorResponse from './handle_error_response'; +import { get } from 'lodash'; import processBucket from './table/process_bucket'; -import { getIndexPatternObject } from './helpers/get_index_pattern'; +import { SearchStrategiesRegister } from '../search_strategies/search_strategies_register'; import { getEsQueryConfig } from './helpers/get_es_query_uisettings'; - +import { getIndexPatternObject } from './helpers/get_index_pattern'; export async function getTableData(req, panel) { - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('data'); - const includeFrozen = await req.getUiSettingsService().get('search:includeFrozen'); - + const panelIndexPattern = panel.index_pattern; + const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy(req, panelIndexPattern); + const searchRequest = searchStrategy.getSearchRequest(req, panelIndexPattern); const esQueryConfig = await getEsQueryConfig(req); - const indexPattern = panel.index_pattern; - const { indexPatternObject, indexPatternString } = await getIndexPatternObject(req, indexPattern); + const { indexPatternObject } = await getIndexPatternObject(req, panelIndexPattern); + const body = buildRequestBody(req, panel, esQueryConfig, indexPatternObject, capabilities); - const params = { - index: indexPatternString, - ignore_throttled: !includeFrozen, - body: buildRequestBody(req, panel, esQueryConfig, indexPatternObject) - }; try { - const resp = await callWithRequest(req, 'search', params); + const [resp] = await searchRequest.search({ body }); const buckets = get(resp, 'aggregations.pivot.buckets', []); return { type: 'table', series: buckets.map(processBucket(panel)) }; } catch (err) { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_agg_value.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_agg_value.js index 57a58cf00cfe4..5bf32ee4ff174 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_agg_value.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_agg_value.js @@ -18,7 +18,7 @@ */ import { get, includes, max, min, sum } from 'lodash'; -import extendStatsTypes from './extended_stats_types'; +import { EXTENDED_STATS_TYPES, METRIC_TYPES } from './metric_types'; const aggFns = { max, @@ -29,7 +29,7 @@ const aggFns = { export default (row, metric) => { // Extended Stats - if (includes(extendStatsTypes, metric.type)) { + if (includes(EXTENDED_STATS_TYPES, metric.type)) { const isStdDeviation = /^std_deviation/.test(metric.type); const modeIsBounds = ~['upper', 'lower'].indexOf(metric.mode); if (isStdDeviation && modeIsBounds) { @@ -38,38 +38,36 @@ export default (row, metric) => { return get(row, `${metric.id}.${metric.type}`); } - // Percentiles - if (metric.type === 'percentile') { - let percentileKey = `${metric.percent}`; - if (!/\./.test(`${metric.percent}`)) { - percentileKey = `${metric.percent}.0`; - } - return row[metric.id].values[percentileKey]; - } - - if (metric.type === 'percentile_rank') { - const percentileRankKey = `${metric.value}`; - return ( - row[metric.id] && - row[metric.id].values && - row[metric.id].values[percentileRankKey] - ); - } + switch (metric.type) { + case METRIC_TYPES.PERCENTILE: + let percentileKey = `${metric.percent}`; + if (!/\./.test(`${metric.percent}`)) { + percentileKey = `${metric.percent}.0`; + } + return row[metric.id].values[percentileKey]; + case METRIC_TYPES.PERCENTILE_RANK: + const percentileRankKey = `${metric.value}`; + return ( + row[metric.id] && + row[metric.id].values && + row[metric.id].values[percentileRankKey] + ); + case METRIC_TYPES.TOP_HIT: + if (row[metric.id].doc_count === 0) return null; + const hits = get(row, [metric.id, 'docs', 'hits', 'hits'], []); + const values = hits.map(doc => { + return get(doc, `_source.${metric.field}`, 0); + }); + const aggWith = (metric.agg_with && aggFns[metric.agg_with]) || aggFns.avg; + return aggWith(values); + case METRIC_TYPES.COUNT: + return get(row, 'doc_count', null); + default: + // Derivatives + const normalizedValue = get(row, `${metric.id}.normalized_value`, null); - if (metric.type === 'top_hit') { - if (row[metric.id].doc_count === 0) return null; - const hits = get(row, [metric.id, 'docs', 'hits', 'hits'], []); - const values = hits.map(doc => { - return get(doc, `_source.${metric.field}`, 0); - }); - const aggWith = (metric.agg_with && aggFns[metric.agg_with]) || aggFns.avg; - return aggWith(values); + // Everything else + const value = get(row, `${metric.id}.value`, null); + return normalizedValue || value; } - - // Derivatives - const normalizedValue = get(row, `${metric.id}.normalized_value`, null); - - // Everything else - const value = get(row, `${metric.id}.value`, null); - return normalizedValue || value; }; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_bucket_size.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_bucket_size.js index cd6cf4206d63c..687cc02853038 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_bucket_size.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_bucket_size.js @@ -22,33 +22,53 @@ import moment from 'moment'; import unitToSeconds from './unit_to_seconds'; import { INTERVAL_STRING_RE, - GTE_INTERVAL_RE + GTE_INTERVAL_RE, } from '../../../../common/interval_regexp'; -export default (req, interval) => { - const from = moment.utc(req.payload.timerange.min); - const to = moment.utc(req.payload.timerange.max); + +const calculateBucketData = (timeInterval, capabilities) => { + const intervalString = capabilities ? capabilities.getValidTimeInterval(timeInterval) : timeInterval; + const intervalStringMatch = intervalString.match(INTERVAL_STRING_RE); + + let bucketSize = Number(intervalStringMatch[1]) * unitToSeconds(intervalStringMatch[2]); + + // don't go too small + if (bucketSize < 1) { + bucketSize = 1; + } + + return { + bucketSize, + intervalString, + }; +}; + +const getTimeRangeBucketSize = ({ min, max }) => { + const from = moment.utc(min); + const to = moment.utc(max); const duration = moment.duration(to.valueOf() - from.valueOf(), 'ms'); - let bucketSize = calculateAuto.near(100, duration).asSeconds(); - if (bucketSize < 1) bucketSize = 1; // don't go too small + + return calculateAuto.near(100, duration).asSeconds(); +}; + +export default (req, interval, capabilities) => { + const bucketSize = getTimeRangeBucketSize(req.payload.timerange); let intervalString = `${bucketSize}s`; - const gteAutoMatch = interval && interval.match(GTE_INTERVAL_RE); + const gteAutoMatch = Boolean(interval) && interval.match(GTE_INTERVAL_RE); + if (gteAutoMatch) { - const intervalStringMatch = gteAutoMatch[1].match(INTERVAL_STRING_RE); - const gteBucketSize = Number(intervalStringMatch[1]) * unitToSeconds(intervalStringMatch[2]); - if (gteBucketSize >= bucketSize) { - return { - bucketSize: gteBucketSize, - intervalString: gteAutoMatch[1] - }; + const bucketData = calculateBucketData(gteAutoMatch[1], capabilities); + + if (bucketData.bucketSize >= bucketSize) { + return bucketData; } } const matches = interval && interval.match(INTERVAL_STRING_RE); + if (matches) { - bucketSize = Number(matches[1]) * unitToSeconds(matches[2]); intervalString = interval; } - return { bucketSize, intervalString }; + return calculateBucketData(intervalString, capabilities); }; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_default_decoration.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_default_decoration.js index e8d6cf075a0bd..9e2c495df0cb1 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_default_decoration.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_default_decoration.js @@ -20,8 +20,21 @@ export default series => { const pointSize = series.point_size != null ? Number(series.point_size) : Number(series.line_width); const showPoints = series.chart_type === 'line' && pointSize !== 0; + let stack; + switch (series.stacked) { + case 'stacked': + case 'percent': + stack = true; + break; + case 'stacked_within_series': + stack = series.id; + break; + default: + stack = false; + } + return { - stack: series.stacked && series.stacked !== 'none' || false, + stack, lines: { show: series.chart_type === 'line' && series.line_width !== 0, fill: Number(series.fill), diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_es_shard_timeout.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_es_shard_timeout.js index 36636d8c57fdc..da4ad46a563f3 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_es_shard_timeout.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_es_shard_timeout.js @@ -16,7 +16,11 @@ * specific language governing permissions and limitations * under the License. */ +import { first, map } from 'rxjs/operators'; -export default function getEsShardTimeout(req) { - return req.server.config().get('elasticsearch.shardTimeout'); +export async function getEsShardTimeout(req) { + return await req.server.core.elasticsearch.legacy.config$.pipe( + first(), + map(config => config.shardTimeout.asMilliseconds()) + ).toPromise(); } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_index_pattern.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_index_pattern.js index beae827f42e5f..2166620de73e2 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_index_pattern.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_index_pattern.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { get } from 'lodash'; export async function getIndexPatternObject(req, indexPatternString) { let defaultIndex; @@ -48,6 +49,6 @@ export async function getIndexPatternObject(req, indexPatternString) { return { indexPatternObject, - indexPatternString: indexPatternString || indexPatternObject.title + indexPatternString: indexPatternString || get(indexPatternObject, 'title', '') }; } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_splits.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_splits.js index 99734f7f131c3..75d1b4d565fe5 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_splits.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/get_splits.js @@ -23,12 +23,20 @@ import _ from 'lodash'; import getLastMetric from './get_last_metric'; import getSplitColors from './get_split_colors'; import { formatKey } from './format_key'; -export default function getSplits(resp, panel, series) { - const meta = _.get(resp, `aggregations.${series.id}.meta`); + +const getTimeSeries = (resp, series) => + _.get(resp, `aggregations.timeseries`) || + _.get(resp, `aggregations.${series.id}.timeseries`); + +export default function getSplits(resp, panel, series, meta) { + if (!meta) { + meta = _.get(resp, `aggregations.${series.id}.meta`); + } + const color = new Color(series.color); const metric = getLastMetric(series); - if (_.has(resp, `aggregations.${series.id}.buckets`)) { - const buckets = _.get(resp, `aggregations.${series.id}.buckets`); + const buckets = _.get(resp, `aggregations.${series.id}.buckets`); + if (buckets) { if (Array.isArray(buckets)) { const size = buckets.length; const colors = getSplitColors(series.color, size, series.split_color_mode); @@ -41,7 +49,7 @@ export default function getSplits(resp, panel, series) { }); } - if(series.split_mode === 'filters' && _.isPlainObject(buckets)) { + if (series.split_mode === 'filters' && _.isPlainObject(buckets)) { return series.split_filters.map(filter => { const bucket = _.get(resp, `aggregations.${series.id}.buckets.${filter.id}`); bucket.id = `${series.id}:${filter.id}`; @@ -54,9 +62,10 @@ export default function getSplits(resp, panel, series) { } } - const timeseries = _.get(resp, `aggregations.${series.id}.timeseries`); + const timeseries = getTimeSeries(resp, series); + const mergeObj = { - timeseries + timeseries, }; series.metrics .filter(m => /_bucket/.test(m.type)) @@ -69,8 +78,8 @@ export default function getSplits(resp, panel, series) { label: series.label || calculateLabel(metric, series.metrics), color: color.string(), ...mergeObj, - meta - } + meta, + }, ]; } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/index.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/index.js index f5159d8b2bf43..01df1a6f54acd 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/index.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/index.js @@ -22,7 +22,6 @@ import getAggValue from './get_agg_value'; import getBucketSize from './get_bucket_size'; import getBucketPath from './get_buckets_path'; import getDefaultDecoration from './get_default_decoration'; -import getEsShardTimeout from './get_es_shard_timeout'; import getLastMetric from './get_last_metric'; import getSiblingAggValue from './get_sibling_agg_value'; import getSplits from './get_splits'; @@ -37,7 +36,6 @@ export default { getBucketSize, getBucketPath, getDefaultDecoration, - getEsShardTimeout, getLastMetric, getSiblingAggValue, getSplits, diff --git a/test/functional/services/remote/browser_driver_api/browser_driver_remote_api.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/metric_types.js similarity index 77% rename from test/functional/services/remote/browser_driver_api/browser_driver_remote_api.js rename to src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/metric_types.js index 3b8e486c2e55f..1143291141dc4 100644 --- a/test/functional/services/remote/browser_driver_api/browser_driver_remote_api.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/metric_types.js @@ -17,15 +17,15 @@ * under the License. */ -import { BrowserDriverApi } from './browser_driver_api'; +export const EXTENDED_STATS_TYPES = [ + 'std_deviation', + 'variance', + 'sum_of_squares' +]; -export function createRemoteBrowserDriverApi(log, url) { - return new BrowserDriverApi({ - url, - - start() { - log.info(`Reusing instance at %j`, url); - } - - }); -} +export const METRIC_TYPES = { + PERCENTILE: 'percentile', + PERCENTILE_RANK: 'percentile_rank', + TOP_HIT: 'top_hit', + COUNT: 'count' +}; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/unit_to_seconds.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/unit_to_seconds.js index dbbbd9a68f1d7..4494883c44edc 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/unit_to_seconds.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/unit_to_seconds.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { INTERVAL_STRING_RE } from '../../../../common/interval_regexp'; const units = { ms: 0.001, @@ -23,11 +24,33 @@ const units = { m: 60, h: 3600, d: 86400, - w: (86400) * 7, // Hum... might be wrong - M: (86400) * 30, // this too... 29,30,31? - y: (86400) * 356 // Leap year? + w: 86400 * 7, // Hum... might be wrong + M: 86400 * 7 * 4, // this too... 29,30,31? + y: 86400 * 7 * 4 * 12, // Leap year? +}; + +export const parseInterval = (intervalString) => { + let value; + let unit; + + if (intervalString) { + const matches = intervalString.match(INTERVAL_STRING_RE); + + value = Number(matches[1]); + unit = matches[2]; + } + + return { value, unit }; +}; + +export const convertIntervalToUnit = (intervalString, unit) => { + const parsedInterval = parseInterval(intervalString); + const value = Number((parsedInterval.value * units[parsedInterval.unit] / units[unit]).toFixed(2)); + + return { value, unit }; }; export default (unit) => { return units[unit]; }; + diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/date_histogram.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/date_histogram.js index 323d5b4911b27..05657842a5e2a 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/date_histogram.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/date_histogram.js @@ -20,12 +20,13 @@ import _ from 'lodash'; import getBucketSize from '../../helpers/get_bucket_size'; import getTimerange from '../../helpers/get_timerange'; -export default function dateHistogram(req, panel, annotation) { +export default function dateHistogram(req, panel, annotation, esQueryConfig, indexPatternObject, capabilities) { return next => doc => { const timeField = annotation.time_field; - const { bucketSize, intervalString } = getBucketSize(req, 'auto'); + const { bucketSize, intervalString } = getBucketSize(req, 'auto', capabilities); const { from, to } = getTimerange(req); - const { timezone } = req.payload.timerange; + const timezone = capabilities.searchTimezone; + _.set(doc, `aggs.${annotation.id}.date_histogram`, { field: timeField, interval: intervalString, diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/query.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/query.js index 2e4f765b21321..882f35a2e0ee2 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/query.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/query.js @@ -21,10 +21,10 @@ import getBucketSize from '../../helpers/get_bucket_size'; import getTimerange from '../../helpers/get_timerange'; import { buildEsQuery } from '@kbn/es-query'; -export default function query(req, panel, annotation, esQueryConfig, indexPattern) { +export default function query(req, panel, annotation, esQueryConfig, indexPattern, capabilities) { return next => doc => { const timeField = annotation.time_field; - const { bucketSize } = getBucketSize(req, 'auto'); + const { bucketSize } = getBucketSize(req, 'auto', capabilities); const { from, to } = getTimerange(req); doc.size = 0; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/__tests__/date_histogram.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/__tests__/date_histogram.js index 3d77d98e56950..34bcf090fecf2 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/__tests__/date_histogram.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/__tests__/date_histogram.js @@ -20,12 +20,17 @@ import dateHistogram from '../date_histogram'; import { expect } from 'chai'; import sinon from 'sinon'; +import { DefaultSearchCapabilities } from '../../../../search_strategies/default_search_capabilities'; describe('dateHistogram(req, panel, series)', () => { let panel; let series; let req; + let capabilities; + let config; + let indexPatternObject; + beforeEach(() => { req = { payload: { @@ -42,17 +47,23 @@ describe('dateHistogram(req, panel, series)', () => { interval: '10s' }; series = { id: 'test' }; + config = { + allowLeadingWildcards: true, + queryStringOptions: {}, + }; + indexPatternObject = {}; + capabilities = new DefaultSearchCapabilities(req, true); }); it('calls next when finished', () => { const next = sinon.spy(); - dateHistogram(req, panel, series)(next)({}); + dateHistogram(req, panel, series, config, indexPatternObject, capabilities)(next)({}); expect(next.calledOnce).to.equal(true); }); it('returns valid date histogram', () => { const next = doc => doc; - const doc = dateHistogram(req, panel, series)(next)({}); + const doc = dateHistogram(req, panel, series, config, indexPatternObject, capabilities)(next)({}); expect(doc).to.eql({ aggs: { test: { @@ -73,7 +84,8 @@ describe('dateHistogram(req, panel, series)', () => { meta: { bucketSize: 10, intervalString: '10s', - timeField: '@timestamp' + timeField: '@timestamp', + seriesId: 'test' } } } @@ -83,7 +95,7 @@ describe('dateHistogram(req, panel, series)', () => { it('returns valid date histogram (offset by 1h)', () => { series.offset_time = '1h'; const next = doc => doc; - const doc = dateHistogram(req, panel, series)(next)({}); + const doc = dateHistogram(req, panel, series, config, indexPatternObject, capabilities)(next)({}); expect(doc).to.eql({ aggs: { test: { @@ -104,7 +116,8 @@ describe('dateHistogram(req, panel, series)', () => { meta: { bucketSize: 10, intervalString: '10s', - timeField: '@timestamp' + timeField: '@timestamp', + seriesId: 'test' } } } @@ -117,7 +130,7 @@ describe('dateHistogram(req, panel, series)', () => { series.series_time_field = 'timestamp'; series.series_interval = '20s'; const next = doc => doc; - const doc = dateHistogram(req, panel, series)(next)({}); + const doc = dateHistogram(req, panel, series, config, indexPatternObject, capabilities)(next)({}); expect(doc).to.eql({ aggs: { test: { @@ -138,7 +151,8 @@ describe('dateHistogram(req, panel, series)', () => { meta: { bucketSize: 20, intervalString: '20s', - timeField: 'timestamp' + timeField: 'timestamp', + seriesId: 'test' } } } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/date_histogram.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/date_histogram.js index b760ef20da053..c04684aab7e4f 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/date_histogram.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/date_histogram.js @@ -21,12 +21,12 @@ import getBucketSize from '../../helpers/get_bucket_size'; import offsetTime from '../../offset_time'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; import { set } from 'lodash'; -export default function dateHistogram(req, panel, series) { +export default function dateHistogram(req, panel, series, esQueryConfig, indexPatternObject, capabilities) { return next => doc => { const { timeField, interval } = getIntervalAndTimefield(panel, series); - const { bucketSize, intervalString } = getBucketSize(req, interval); + const { bucketSize, intervalString } = getBucketSize(req, interval, capabilities); const { from, to } = offsetTime(req, series.offset_time); - const { timezone } = req.payload.timerange; + const timezone = capabilities.searchTimezone; set(doc, `aggs.${series.id}.aggs.timeseries.date_histogram`, { field: timeField, @@ -41,7 +41,8 @@ export default function dateHistogram(req, panel, series) { set(doc, `aggs.${series.id}.meta`, { timeField, intervalString, - bucketSize + bucketSize, + seriesId: series.id, }); return next(doc); }; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/index.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/index.js index 8008a63e10220..02e084bc779a1 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/index.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/index.js @@ -26,6 +26,7 @@ import dateHistogram from './date_histogram'; import metricBuckets from './metric_buckets'; import siblingBuckets from './sibling_buckets'; import filterRatios from './filter_ratios'; +import normalizeQuery from './normalize_query'; export default [ query, @@ -36,5 +37,6 @@ export default [ dateHistogram, metricBuckets, siblingBuckets, - filterRatios + filterRatios, + normalizeQuery ]; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/metric_buckets.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/metric_buckets.js index ed96bebc9c68c..19aad8f37d825 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/metric_buckets.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/metric_buckets.js @@ -21,14 +21,14 @@ import _ from 'lodash'; import getBucketSize from '../../helpers/get_bucket_size'; import bucketTransform from '../../helpers/bucket_transform'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; -export default function metricBuckets(req, panel, series) { +export default function metricBuckets(req, panel, series, esQueryConfig, indexPatternObject, capabilities) { return next => doc => { const { interval } = getIntervalAndTimefield(panel, series); const { intervalString - } = getBucketSize(req, interval); + } = getBucketSize(req, interval, capabilities); series.metrics .filter(row => !/_bucket$/.test(row.type) && !/^series/.test(row.type)) .forEach(metric => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/normalize_query.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/normalize_query.js new file mode 100644 index 0000000000000..df2a829b90024 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/normalize_query.js @@ -0,0 +1,47 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { set, get, isEmpty } = require('lodash'); + +const isEmptyFilter = (filter = {}) => Boolean(filter.match_all) && isEmpty(filter.match_all); + +/* For grouping by the 'Everything', the splitByEverything request processor + * creates fake .filter.match_all filter (see split_by_everything.js) to simplify the request processors code. + * But “filters” are not supported by all of available search strategies (e.g. Rollup search). + * This method removes that aggregation. + */ +function removeEmptyTopLevelAggregation(doc, series) { + const filter = get(doc, `aggs.${series.id}.filter`); + + if (isEmptyFilter(filter)) { + const meta = get(doc, `aggs.${series.id}.meta`); + set(doc, `aggs`, doc.aggs[series.id].aggs); + set(doc, `aggs.timeseries.meta`, meta); + } + + return doc; +} + +/* Last query handler in the chain. You can use this handler + * as the last place where you can modify the "doc" (request body) object before sending it to ES. + */ +export default function normalizeQuery(req, panel, series) { + return next => doc => { + return next(removeEmptyTopLevelAggregation(doc, series)); + }; +} diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/sibling_buckets.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/sibling_buckets.js index 9f2bc1d4cba0f..351ff2bf27f62 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/sibling_buckets.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/sibling_buckets.js @@ -21,14 +21,14 @@ import _ from 'lodash'; import getBucketSize from '../../helpers/get_bucket_size'; import bucketTransform from '../../helpers/bucket_transform'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; -export default function siblingBuckets(req, panel, series) { +export default function siblingBuckets(req, panel, series, esQueryConfig, indexPatternObject, capabilities) { return next => doc => { const { interval } = getIntervalAndTimefield(panel, series); const { bucketSize - } = getBucketSize(req, interval); + } = getBucketSize(req, interval, capabilities); series.metrics .filter(row => /_bucket$/.test(row.type)) .forEach(metric => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/filter_ratios.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/filter_ratios.js index dcafbe39cd153..ef4bf22e14c0f 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/filter_ratios.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/filter_ratios.js @@ -23,7 +23,7 @@ import bucketTransform from '../../helpers/bucket_transform'; import _ from 'lodash'; import { calculateAggRoot } from './calculate_agg_root'; export default function ratios(req, panel) { - return () => doc => { + return next => doc => { panel.series.forEach(column => { const aggRoot = calculateAggRoot(doc, column); if (column.metrics.some(filter)) { @@ -63,6 +63,6 @@ export default function ratios(req, panel) { }); } }); - return doc; + return next(doc); }; } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/index.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/index.js index f2359e5bfffde..0e160e8333c5c 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/index.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/index.js @@ -25,6 +25,7 @@ import dateHistogram from './date_histogram'; import metricBuckets from './metric_buckets'; import siblingBuckets from './sibling_buckets'; import filterRatios from './filter_ratios'; +import normalizeQuery from './normalize_query'; export default [ query, @@ -34,5 +35,6 @@ export default [ dateHistogram, metricBuckets, siblingBuckets, - filterRatios + filterRatios, + normalizeQuery ]; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/normalize_query.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/normalize_query.js new file mode 100644 index 0000000000000..2d8eb281858bf --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/normalize_query.js @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { set, get, isEmpty, forEach } = require('lodash'); + +const isEmptyFilter = (filter = {}) => Boolean(filter.match_all) && isEmpty(filter.match_all); + +/* Last query handler in the chain. You can use this handler + * as the last place where you can modify the "doc" (request body) object before sending it to ES. + */ +export default function normalizeQuery() { + return () => doc => { + const series = get(doc, 'aggs.pivot.aggs'); + const normalizedSeries = {}; + + forEach(series, (value, seriesId) => { + const filter = get(value, `filter`); + + if (isEmptyFilter(filter)) { + const agg = get(value, 'aggs.timeseries'); + const meta = { + ...get(value, 'meta'), + seriesId + }; + set(normalizedSeries, `${seriesId}`, agg); + set(normalizedSeries, `${seriesId}.meta`, meta); + } else { + set(normalizedSeries, `${seriesId}`, value); + } + }); + + set(doc, 'aggs.pivot.aggs', normalizedSeries); + + return doc; + }; +} diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/math.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/math.js index 0fa97bfb109e1..ada43f1e35cf5 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/math.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/math.js @@ -25,7 +25,7 @@ import getSplits from '../../helpers/get_splits'; import mapBucket from '../../helpers/map_bucket'; import { evaluate } from 'tinymath'; -export function mathAgg(resp, panel, series) { +export function mathAgg(resp, panel, series, meta) { return next => results => { const mathMetric = last(series.metrics); if (mathMetric.type !== 'math') return next(results); @@ -38,7 +38,7 @@ export function mathAgg(resp, panel, series) { return true; }); const decoration = getDefaultDecoration(series); - const splits = getSplits(resp, panel, series); + const splits = getSplits(resp, panel, series, meta); const mathSeries = splits.map(split => { if (mathMetric.variables.length) { // Gather the data for the splits. The data will either be a sibling agg or diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/percentile.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/percentile.js index 79534452665a9..e016aad1915b1 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/percentile.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/percentile.js @@ -22,12 +22,12 @@ import getAggValue from '../../helpers/get_agg_value'; import getDefaultDecoration from '../../helpers/get_default_decoration'; import getSplits from '../../helpers/get_splits'; import getLastMetric from '../../helpers/get_last_metric'; -export default function percentile(resp, panel, series) { +export default function percentile(resp, panel, series, meta) { return next => results => { const metric = getLastMetric(series); if (metric.type !== 'percentile') return next(results); - getSplits(resp, panel, series).forEach((split) => { + getSplits(resp, panel, series, meta).forEach((split) => { metric.percentiles.forEach(percentile => { const label = (split.label) + ` (${percentile.value})`; const data = split.timeseries.buckets.map(bucket => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_deviation_bands.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_deviation_bands.js index 7a52ef26e72ba..5d4e6991fe524 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_deviation_bands.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_deviation_bands.js @@ -21,11 +21,11 @@ import _ from 'lodash'; import getSplits from '../../helpers/get_splits'; import getLastMetric from '../../helpers/get_last_metric'; import mapBucket from '../../helpers/map_bucket'; -export default function stdDeviationBands(resp, panel, series) { +export default function stdDeviationBands(resp, panel, series, meta) { return next => results => { const metric = getLastMetric(series); if (metric.type === 'std_deviation' && metric.mode === 'band') { - getSplits(resp, panel, series).forEach((split) => { + getSplits(resp, panel, series, meta).forEach((split) => { const upper = split.timeseries.buckets.map(mapBucket(_.assign({}, metric, { mode: 'upper' }))); const lower = split.timeseries.buckets.map(mapBucket(_.assign({}, metric, { mode: 'lower' }))); results.push({ diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_deviation_sibling.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_deviation_sibling.js index db26760e30fde..45f5a0eb6bf73 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_deviation_sibling.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_deviation_sibling.js @@ -21,11 +21,11 @@ import _ from 'lodash'; import getSplits from '../../helpers/get_splits'; import getLastMetric from '../../helpers/get_last_metric'; import getSiblingAggValue from '../../helpers/get_sibling_agg_value'; -export default function stdDeviationSibling(resp, panel, series) { +export default function stdDeviationSibling(resp, panel, series, meta) { return next => results => { const metric = getLastMetric(series); if (metric.mode === 'band' && metric.type === 'std_deviation_bucket') { - getSplits(resp, panel, series).forEach((split) => { + getSplits(resp, panel, series, meta).forEach((split) => { const mapBucketByMode = (mode) => { return bucket => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_metric.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_metric.js index bc3cf9dab6338..06030a09f2510 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_metric.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_metric.js @@ -21,7 +21,7 @@ import getDefaultDecoration from '../../helpers/get_default_decoration'; import getSplits from '../../helpers/get_splits'; import getLastMetric from '../../helpers/get_last_metric'; import mapBucket from '../../helpers/map_bucket'; -export default function stdMetric(resp, panel, series) { +export default function stdMetric(resp, panel, series, meta) { return next => results => { const metric = getLastMetric(series); if (metric.type === 'std_deviation' && metric.mode === 'band') { @@ -32,7 +32,7 @@ export default function stdMetric(resp, panel, series) { } if (/_bucket$/.test(metric.type)) return next(results); const decoration = getDefaultDecoration(series); - getSplits(resp, panel, series).forEach(split => { + getSplits(resp, panel, series, meta).forEach(split => { const data = split.timeseries.buckets.map(mapBucket(metric)); results.push({ id: `${split.id}`, diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_sibling.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_sibling.js index eac35d459b4a1..c3784e96e7390 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_sibling.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/series/std_sibling.js @@ -21,7 +21,7 @@ import getDefaultDecoration from '../../helpers/get_default_decoration'; import getSplits from '../../helpers/get_splits'; import getLastMetric from '../../helpers/get_last_metric'; import getSiblingAggValue from '../../helpers/get_sibling_agg_value'; -export default function stdSibling(resp, panel, series) { +export default function stdSibling(resp, panel, series, meta) { return next => results => { const metric = getLastMetric(series); @@ -29,7 +29,7 @@ export default function stdSibling(resp, panel, series) { if (metric.type === 'std_deviation_bucket' && metric.mode === 'band') return next(results); const decoration = getDefaultDecoration(series); - getSplits(resp, panel, series).forEach((split) => { + getSplits(resp, panel, series, meta).forEach((split) => { const data = split.timeseries.buckets.map(bucket => { return [bucket.key, getSiblingAggValue(split, metric)]; }); diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/table/index.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/table/index.js index adb6c7d7e2fa1..9e83916cdfc77 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/table/index.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/table/index.js @@ -21,11 +21,12 @@ import stdMetric from './std_metric'; import stdSibling from './std_sibling'; import seriesAgg from './series_agg'; +import percentile from './percentile'; import { math } from './math'; import { dropLastBucketFn } from './drop_last_bucket'; export default [ - // percentile, + percentile, stdMetric, stdSibling, math, diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/table/percentile.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/table/percentile.js index 396510f42eca4..3061a407991f3 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/table/percentile.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/response_processors/table/percentile.js @@ -16,28 +16,31 @@ * specific language governing permissions and limitations * under the License. */ - -import _ from 'lodash'; -import getAggValue from '../../helpers/get_agg_value'; +import { last } from 'lodash'; import getSplits from '../../helpers/get_splits'; import getLastMetric from '../../helpers/get_last_metric'; -export default function percentile(resp, panel, series) { +export default function percentile(bucket, panel, series) { return next => results => { const metric = getLastMetric(series); if (metric.type !== 'percentile') return next(results); - getSplits(resp, panel, series).forEach((split) => { - const label = (split.label) + ` (${series.value})`; - const data = split.timeseries.buckets.map(bucket => { - const m = _.assign({}, metric, { percent: series.value }); - return [bucket.key, getAggValue(bucket, m)]; - }); + const fakeResp = { aggregations: bucket }; + + getSplits(fakeResp, panel, series).forEach(split => { + + // table allows only one percentile in a series (the last one will be chosen in case of several) + const percentile = last(metric.percentiles); + let percentileKey = percentile.value; + if (!/\./.test(percentileKey)) { + percentileKey = `${percentileKey}.0`; + } + + const data = split.timeseries.buckets.map(bucket => [bucket.key, bucket[metric.id].values[percentileKey]]); + results.push({ - id: `${percentile.id}:${split.id}`, - label, - data, + id: split.id, + data }); - }); return next(results); }; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/series/__tests__/build_request_body.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/series/__tests__/build_request_body.js index cb944bb8363fa..195ae5b01c0f9 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/series/__tests__/build_request_body.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/series/__tests__/build_request_body.js @@ -75,18 +75,26 @@ const body = JSON.parse(` } `); -import buildRequestBody from '../build_request_body'; +import sinon from 'sinon'; import { expect } from 'chai'; +import { buildRequestBody } from '../build_request_body'; describe('buildRequestBody(req)', () => { it('returns a valid body', () => { const panel = body.panels[0]; const series = panel.series[0]; + const getValidTimeInterval = sinon.spy(() => '10s'); + const capabilities = { + searchTimezone: 'UTC', + getValidTimeInterval + }; const config = { allowLeadingWildcards: true, queryStringOptions: {}, }; - const doc = buildRequestBody({ payload: body }, panel, series, config); + const indexPatternObject = {}; + const doc = buildRequestBody({ payload: body }, panel, series, config, indexPatternObject, capabilities); + expect(doc).to.eql({ size: 0, query: { @@ -121,42 +129,36 @@ describe('buildRequestBody(req)', () => { } }, aggs: { - 'c9b5f9c0-e403-11e6-be91-6f7688e9fac7': { - filter: { - match_all: {} - }, - meta: { - timeField: '@timestamp', - bucketSize: 10, - intervalString: '10s' - }, + timeseries: { aggs: { - timeseries: { - date_histogram: { - field: '@timestamp', - interval: '10s', - min_doc_count: 0, - time_zone: 'UTC', - extended_bounds: { - min: 1485463055881, - max: 1485463955881 - } - }, - aggs: { - 'c9b5f9c1-e403-11e6-be91-6f7688e9fac7': { - bucket_script: { - buckets_path: { - count: '_count' - }, - script: { - source: 'count * 1', - lang: 'expression' - }, - gap_policy: 'skip' - } + 'c9b5f9c1-e403-11e6-be91-6f7688e9fac7': { + bucket_script: { + buckets_path: { + count: '_count' + }, + gap_policy: 'skip', + script: { + lang: 'expression', + source: 'count * 1' } } } + }, + date_histogram: { + extended_bounds: { + max: 1485463955881, + min: 1485463055881 + }, + field: '@timestamp', + interval: '10s', + min_doc_count: 0, + time_zone: 'UTC' + }, + meta: { + bucketSize: 10, + intervalString: '10s', + seriesId: 'c9b5f9c0-e403-11e6-be91-6f7688e9fac7', + timeField: '@timestamp' } } } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/series/build_request_body.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/series/build_request_body.js index c25127b68a6bc..a5b724e11ef55 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/series/build_request_body.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/series/build_request_body.js @@ -20,10 +20,21 @@ import buildProcessorFunction from '../build_processor_function'; import processors from '../request_processors/series'; -function buildRequestBody(req, panel, series, esQueryConfig, indexPattern) { - const processor = buildProcessorFunction(processors, req, panel, series, esQueryConfig, indexPattern); +/** + * Builds series request body + * + * @param {...args}: [ + * req: {Object} - a request object, + * panel: {Object} - a panel object, + * series: {Object} - an series object, + * esQueryConfig: {Object} - es query config object, + * indexPatternObject: {Object} - an index pattern object, + * capabilities: {Object} - a search capabilities object + * ] + * @returns {Object} doc - processed body + */ +export function buildRequestBody(...args) { + const processor = buildProcessorFunction(processors, ...args); const doc = processor({}); return doc; } - -export default buildRequestBody; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/series/get_request_params.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/series/get_request_params.js index d75192f01de2f..581561a0cbce4 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/series/get_request_params.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/series/get_request_params.js @@ -16,26 +16,28 @@ * specific language governing permissions and limitations * under the License. */ - -import buildRequestBody from './build_request_body'; +import { buildRequestBody } from './build_request_body'; +import { getEsShardTimeout } from '../helpers/get_es_shard_timeout'; import { getIndexPatternObject } from '../helpers/get_index_pattern'; -import getEsShardTimeout from '../helpers/get_es_shard_timeout'; -export default async (req, panel, series, esQueryConfig) => { +export async function getSeriesRequestParams(req, panel, series, esQueryConfig, capabilities) { + const bodies = []; const indexPattern = series.override_index_pattern && series.series_index_pattern || panel.index_pattern; const { indexPatternObject, indexPatternString } = await getIndexPatternObject(req, indexPattern); - const request = buildRequestBody(req, panel, series, esQueryConfig, indexPatternObject); - const esShardTimeout = getEsShardTimeout(req); + const request = buildRequestBody(req, panel, series, esQueryConfig, indexPatternObject, capabilities); + const esShardTimeout = await getEsShardTimeout(req); + + if (capabilities.batchRequestsSupport) { + bodies.push({ + index: indexPatternString, + }); + } if (esShardTimeout > 0) { request.timeout = `${esShardTimeout}ms`; } - return [ - { - index: indexPatternString, - ignoreUnavailable: true, - }, - request, - ]; -}; + bodies.push(request); + + return bodies; +} diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/series/handle_response_body.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/series/handle_response_body.js index f732db82f45ed..cd108139fffe7 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/series/handle_response_body.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/series/handle_response_body.js @@ -44,9 +44,11 @@ export default function handleResponseBody(panel) { }) ); } - const seriesId = keys[0]; - const series = panel.series.find(s => s.id === seriesId); - const processor = buildProcessorFunction(processors, resp, panel, series); + const [ seriesId ] = keys; + const meta = get(resp, `aggregations.${seriesId}.meta`, {}); + const series = panel.series.find(s => s.id === (meta.seriesId || seriesId)); + const processor = buildProcessorFunction(processors, resp, panel, series, meta); + return processor([]); }; } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/table/build_request_body.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/table/build_request_body.js index 7e509a5ebf2e5..349863d9cb6c0 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/table/build_request_body.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/table/build_request_body.js @@ -20,8 +20,8 @@ import buildProcessorFunction from '../build_processor_function'; import processors from '../request_processors/table'; -function buildRequestBody(req, panel, esQueryConfig, indexPattern) { - const processor = buildProcessorFunction(processors, req, panel, esQueryConfig, indexPattern); +function buildRequestBody(...args) { + const processor = buildProcessorFunction(processors, ...args); const doc = processor({}); return doc; } diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/table/process_bucket.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/table/process_bucket.js index a42b0f4eefecc..fcbae1518924e 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/table/process_bucket.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/table/process_bucket.js @@ -21,10 +21,21 @@ import buildProcessorFunction from '../build_processor_function'; import processors from '../response_processors/table'; import getLastValue from '../../../../common/get_last_value'; import regression from 'regression'; -import { first, get } from 'lodash'; +import { first, get, set } from 'lodash'; export default function processBucket(panel) { return bucket => { const series = panel.series.map(series => { + const timeseries = get(bucket, `${series.id}.timeseries`); + const buckets = get(bucket, `${series.id}.buckets`); + + if (!timeseries && buckets) { + const meta = get(bucket, `${series.id}.meta`); + const timeseries = { + buckets: get(bucket, `${series.id}.buckets`) + }; + set(bucket, series.id, { meta, timeseries }); + } + const processor = buildProcessorFunction(processors, bucket, panel, series); const result = first(processor([])); if (!result) return null; diff --git a/src/legacy/core_plugins/status_page/public/status_page.js b/src/legacy/core_plugins/status_page/public/status_page.js index f6f6b3630a01c..7aa770b076cf3 100644 --- a/src/legacy/core_plugins/status_page/public/status_page.js +++ b/src/legacy/core_plugins/status_page/public/status_page.js @@ -17,7 +17,6 @@ * under the License. */ -import 'ui/autoload/modules'; import 'ui/autoload/styles'; import 'ui/i18n'; import chrome from 'ui/chrome'; diff --git a/src/legacy/core_plugins/table_vis/public/table_vis.html b/src/legacy/core_plugins/table_vis/public/table_vis.html index d751db69f2ef3..bfe623b95f864 100644 --- a/src/legacy/core_plugins/table_vis/public/table_vis.html +++ b/src/legacy/core_plugins/table_vis/public/table_vis.html @@ -1,7 +1,7 @@
- +

diff --git a/src/legacy/core_plugins/testbed/public/index.js b/src/legacy/core_plugins/testbed/public/index.js index 94c927496ad15..c6687de249cf2 100644 --- a/src/legacy/core_plugins/testbed/public/index.js +++ b/src/legacy/core_plugins/testbed/public/index.js @@ -17,4 +17,4 @@ * under the License. */ -import './testbed'; \ No newline at end of file +import './testbed'; diff --git a/src/legacy/core_plugins/tile_map/public/coordinate_maps_visualization.js b/src/legacy/core_plugins/tile_map/public/coordinate_maps_visualization.js index b1efb35bae3d0..67c894f4211bd 100644 --- a/src/legacy/core_plugins/tile_map/public/coordinate_maps_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/coordinate_maps_visualization.js @@ -22,7 +22,7 @@ import { GeohashLayer } from './geohash_layer'; import { BaseMapsVisualizationProvider } from './base_maps_visualization'; import { TileMapTooltipFormatterProvider } from './editors/_tooltip_formatter'; -export function CoordinateMapsVisualizationProvider(Notifier, Private) { +export function CoordinateMapsVisualizationProvider(Private) { const BaseMapsVisualization = Private(BaseMapsVisualizationProvider); const tooltipFormatter = Private(TileMapTooltipFormatterProvider); @@ -32,7 +32,6 @@ export function CoordinateMapsVisualizationProvider(Notifier, Private) { constructor(element, vis) { super(element, vis); this._geohashLayer = null; - this._notify = new Notifier({ location: 'Coordinate Map' }); } async _makeKibanaMap() { diff --git a/src/legacy/core_plugins/timelion/init.js b/src/legacy/core_plugins/timelion/init.js index eecebfb81fdf0..b75baff5ed967 100644 --- a/src/legacy/core_plugins/timelion/init.js +++ b/src/legacy/core_plugins/timelion/init.js @@ -56,8 +56,6 @@ export default function (server) { const config = server.config(); return { kbnIndex: config.get('kibana.index'), - esShardTimeout: config.get('elasticsearch.shardTimeout'), - esApiVersion: config.get('elasticsearch.apiVersion') }; }); } diff --git a/src/legacy/core_plugins/timelion/server/fit_functions/nearest.js b/src/legacy/core_plugins/timelion/server/fit_functions/nearest.js index db3a675dde719..feacbb02ce195 100644 --- a/src/legacy/core_plugins/timelion/server/fit_functions/nearest.js +++ b/src/legacy/core_plugins/timelion/server/fit_functions/nearest.js @@ -43,4 +43,4 @@ export default function nearest(dataTuples, targetTuples) { return [bucket[0], closest[1]]; }); -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/timelion/server/fit_functions/none.js b/src/legacy/core_plugins/timelion/server/fit_functions/none.js index 87b0df2b0f491..e46d9f44a96be 100644 --- a/src/legacy/core_plugins/timelion/server/fit_functions/none.js +++ b/src/legacy/core_plugins/timelion/server/fit_functions/none.js @@ -23,4 +23,4 @@ // Does not resample at all. export default function none(dataTuples) { return dataTuples; -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/timelion/server/lib/to_milliseconds.js b/src/legacy/core_plugins/timelion/server/lib/to_milliseconds.js index 394ee5c4dd313..2dd5cad4cad82 100644 --- a/src/legacy/core_plugins/timelion/server/lib/to_milliseconds.js +++ b/src/legacy/core_plugins/timelion/server/lib/to_milliseconds.js @@ -51,4 +51,4 @@ export default function (expr) { return parseFloat(match[1] || 1) * vals[match[2]]; } -} \ No newline at end of file +} diff --git a/src/legacy/core_plugins/timelion/server/series_functions/__tests__/es.js b/src/legacy/core_plugins/timelion/server/series_functions/__tests__/es.js index cbeac18e3542f..de74e6edf1e50 100644 --- a/src/legacy/core_plugins/timelion/server/series_functions/__tests__/es.js +++ b/src/legacy/core_plugins/timelion/server/series_functions/__tests__/es.js @@ -198,27 +198,16 @@ describe(filename, () => { }); describe('timeouts', () => { - let sandbox; - - beforeEach(() => { - sandbox = sinon.createSandbox(); - }); - - afterEach(() => { - sandbox.restore(); - }); - it('sets the timeout on the request', () => { config.index = 'beer'; - const request = fn(config, tlConfig, emptyScriptedFields); + const request = fn(config, tlConfig, emptyScriptedFields, 30000); expect(request.timeout).to.equal('30000ms'); }); it('sets no timeout if elasticsearch.shardTimeout is set to 0', () => { - sandbox.stub(tlConfig.server.config(), 'get').withArgs('elasticsearch.shardTimeout').returns(0); config.index = 'beer'; - const request = fn(config, tlConfig, emptyScriptedFields); + const request = fn(config, tlConfig, emptyScriptedFields, 0); expect(request).to.not.have.property('timeout'); }); diff --git a/src/legacy/core_plugins/timelion/server/series_functions/__tests__/fixtures/tlConfig.js b/src/legacy/core_plugins/timelion/server/series_functions/__tests__/fixtures/tlConfig.js index 0ad145f68ce4f..e0f95eca2adf3 100644 --- a/src/legacy/core_plugins/timelion/server/series_functions/__tests__/fixtures/tlConfig.js +++ b/src/legacy/core_plugins/timelion/server/series_functions/__tests__/fixtures/tlConfig.js @@ -18,23 +18,12 @@ */ import moment from 'moment'; +import { of } from 'rxjs'; import sinon from 'sinon'; import timelionDefaults from '../../../lib/get_namespaced_settings'; import esResponse from './es_response'; export default function () { - - const config = { - get(key) { - switch (key) { - case 'elasticsearch.shardTimeout': - return 30000; - default: - throw new Error(`unexpected config ${key}`); - } - } - }; - const functions = require('../../../lib/load_functions')('series_functions'); const server = { plugins: { @@ -52,7 +41,11 @@ export default function () { }) } }, - config: () => config, + core: { + elasticsearch: { + legacy: { config$: of({ shardTimeout: moment.duration(30000) }) } + } + }, }; const tlConfig = require('../../../handlers/lib/tl_config.js')({ diff --git a/src/legacy/core_plugins/timelion/server/series_functions/es/index.js b/src/legacy/core_plugins/timelion/server/series_functions/es/index.js index 9de47a57e0ba6..e3ede24ff7e48 100644 --- a/src/legacy/core_plugins/timelion/server/series_functions/es/index.js +++ b/src/legacy/core_plugins/timelion/server/series_functions/es/index.js @@ -17,6 +17,7 @@ * under the License. */ +import { first, map } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import _ from 'lodash'; import Datasource from '../../lib/classes/datasource'; @@ -126,7 +127,12 @@ export default new Datasource('es', { }); } - const body = buildRequest(config, tlConfig, scriptedFields); + const esShardTimeout = await tlConfig.server.core.elasticsearch.legacy.config$.pipe( + first(), + map(config => config.shardTimeout.asMilliseconds()) + ).toPromise(); + + const body = buildRequest(config, tlConfig, scriptedFields, esShardTimeout); const { callWithRequest } = tlConfig.server.plugins.elasticsearch.getCluster('data'); const resp = await callWithRequest(tlConfig.request, 'search', body); diff --git a/src/legacy/core_plugins/timelion/server/series_functions/es/lib/build_request.js b/src/legacy/core_plugins/timelion/server/series_functions/es/lib/build_request.js index 6850dd902bce5..68b6aa1e5108c 100644 --- a/src/legacy/core_plugins/timelion/server/series_functions/es/lib/build_request.js +++ b/src/legacy/core_plugins/timelion/server/series_functions/es/lib/build_request.js @@ -21,7 +21,7 @@ import _ from 'lodash'; import { buildAggBody } from './agg_body'; import createDateAgg from './create_date_agg'; -export default function buildRequest(config, tlConfig, scriptedFields) { +export default function buildRequest(config, tlConfig, scriptedFields, timeout) { const bool = { must: [] }; @@ -78,7 +78,6 @@ export default function buildRequest(config, tlConfig, scriptedFields) { } }; - const timeout = tlConfig.server.config().get('elasticsearch.shardTimeout'); if (timeout) { request.timeout = `${timeout}ms`; } diff --git a/test/functional/services/remote/browser_driver_api/ping.js b/src/legacy/server/core/index.ts similarity index 69% rename from test/functional/services/remote/browser_driver_api/ping.js rename to src/legacy/server/core/index.ts index 65b62a8b7b4dc..bb00c47b46a9d 100644 --- a/test/functional/services/remote/browser_driver_api/ping.js +++ b/src/legacy/server/core/index.ts @@ -17,19 +17,14 @@ * under the License. */ -import request from 'request'; -import { fromNode as fcb } from 'bluebird'; +import { Server } from 'hapi'; +import KbnServer from '../kbn_server'; -export async function ping(url) { - try { - await Promise.race([ - fcb(cb => request(url, cb)), - new Promise((resolve, reject) => { - setTimeout(() => reject(new Error('timeout')), 1000); - }) - ]); - return true; - } catch (err) { - return false; - } +/** + * Exposes `kbnServer.core` through Hapi API. + * @param kbnServer KbnServer singleton instance. + * @param server Hapi server instance to expose `core` on. + */ +export function coreMixin(kbnServer: KbnServer, server: Server) { + server.decorate('server', 'core', kbnServer.core); } diff --git a/src/legacy/server/index_patterns/service/lib/errors.test.js b/src/legacy/server/index_patterns/service/lib/errors.test.js index 41a1e7ea078ee..1abcded9d60b4 100644 --- a/src/legacy/server/index_patterns/service/lib/errors.test.js +++ b/src/legacy/server/index_patterns/service/lib/errors.test.js @@ -20,4 +20,4 @@ test('test', () => { // errors module is tested in test/api_integration/apis/index_patterns/es_errors/errors.js // so it can get real errors from elasticsearch and the es client to test with -}); \ No newline at end of file +}); diff --git a/src/legacy/server/kbn_server.d.ts b/src/legacy/server/kbn_server.d.ts index b06086b272ba8..71b43123e84d6 100644 --- a/src/legacy/server/kbn_server.d.ts +++ b/src/legacy/server/kbn_server.d.ts @@ -55,6 +55,7 @@ declare module 'hapi' { type KbnMixinFunc = (kbnServer: KbnServer, server: Server, config: any) => Promise | void; export default class KbnServer { + public readonly core: any; public server: Server; public inject: Server['inject']; diff --git a/src/legacy/server/kbn_server.js b/src/legacy/server/kbn_server.js index 4fee05e60ca68..002cd9771ef25 100644 --- a/src/legacy/server/kbn_server.js +++ b/src/legacy/server/kbn_server.js @@ -24,6 +24,7 @@ import { Config } from './config'; import loggingConfiguration from './logging/configuration'; import configSetupMixin from './config/setup'; import httpMixin from './http'; +import { coreMixin } from './core'; import { loggingMixin } from './logging'; import warningsMixin from './warnings'; import { usageMixin } from './usage'; @@ -64,6 +65,8 @@ export default class KbnServer { // sets this.server httpMixin, + coreMixin, + // adds methods for extending this.server serverExtensionsMixin, loggingMixin, diff --git a/src/legacy/server/sample_data/data_sets/flights/field_mappings.js b/src/legacy/server/sample_data/data_sets/flights/field_mappings.js index 41680466643b9..502ca9944dc87 100644 --- a/src/legacy/server/sample_data/data_sets/flights/field_mappings.js +++ b/src/legacy/server/sample_data/data_sets/flights/field_mappings.js @@ -102,4 +102,4 @@ export const fieldMappings = { FlightTimeHour: { type: 'keyword' } -}; \ No newline at end of file +}; diff --git a/src/legacy/server/sample_data/routes/lib/create_index_name.test.js b/src/legacy/server/sample_data/routes/lib/create_index_name.test.js index f0a3bf6cd5985..5f8b29fabdd76 100644 --- a/src/legacy/server/sample_data/routes/lib/create_index_name.test.js +++ b/src/legacy/server/sample_data/routes/lib/create_index_name.test.js @@ -25,4 +25,4 @@ test('should include sampleDataSetId and dataIndexId in elasticsearch index name test('should only include sampleDataSetId when sampleDataSetId and dataIndexId are identical', async () => { expect(createIndexName('flights', 'flights')).toBe('kibana_sample_data_flights'); -}); \ No newline at end of file +}); diff --git a/src/legacy/server/sass/build.js b/src/legacy/server/sass/build.js index 831ab2a195298..f33acbd1abd74 100644 --- a/src/legacy/server/sass/build.js +++ b/src/legacy/server/sass/build.js @@ -57,7 +57,7 @@ const makeAsset = (request, { path, root, boundry, copyRoot, urlRoot }) => { }; export class Build { - constructor({ log, sourcePath, targetPath, urlImports, theme }) { + constructor({ log, sourcePath, targetPath, urlImports, theme, sourceMap = true, outputStyle = 'nested' }) { this.log = log; this.sourcePath = sourcePath; this.sourceDir = dirname(this.sourcePath); @@ -66,6 +66,8 @@ export class Build { this.urlImports = urlImports; this.theme = theme; this.includedFiles = [sourcePath]; + this.sourceMap = sourceMap; + this.outputStyle = outputStyle; } /** @@ -88,8 +90,9 @@ export class Build { const rendered = await renderSass({ file: this.sourcePath, outFile: this.targetPath, - sourceMap: true, - sourceMapEmbed: true, + sourceMap: this.sourceMap, + outputStyle: this.outputStyle, + sourceMapEmbed: this.sourceMap, includePaths: [ resolve(__dirname, '../../../../node_modules'), ], diff --git a/src/legacy/server/sass/build_all.js b/src/legacy/server/sass/build_all.js index c192e80154f80..cd209549a1d37 100644 --- a/src/legacy/server/sass/build_all.js +++ b/src/legacy/server/sass/build_all.js @@ -21,7 +21,7 @@ import { resolve } from 'path'; import { Build } from './build'; -export async function buildAll(styleSheets, log, buildDir) { +export async function buildAll({ styleSheets, log, buildDir, sourceMap, outputStyle }) { const bundles = await Promise.all(styleSheets.map(async styleSheet => { if (!styleSheet.localPath.endsWith('.scss')) { @@ -31,6 +31,8 @@ export async function buildAll(styleSheets, log, buildDir) { const bundle = new Build({ sourcePath: styleSheet.localPath, log, + sourceMap, + outputStyle, theme: styleSheet.theme, targetPath: resolve(buildDir, styleSheet.publicPath), urlImports: styleSheet.urlImports diff --git a/src/legacy/server/sass/index.js b/src/legacy/server/sass/index.js index 5da7cd32b9373..7bd7c79d34fe6 100644 --- a/src/legacy/server/sass/index.js +++ b/src/legacy/server/sass/index.js @@ -45,7 +45,11 @@ export async function sassMixin(kbnServer, server, config) { }; try { - scssBundles = await buildAll(kbnServer.uiExports.styleSheetPaths, log, fromRoot('built_assets/css')); + scssBundles = await buildAll({ + styleSheets: kbnServer.uiExports.styleSheetPaths, + log, + buildDir: fromRoot('built_assets/css') + }); scssBundles.forEach(bundle => { bundle.includedFiles.forEach(file => trackedFiles.add(file)); diff --git a/src/legacy/server/saved_objects/migrations/core/document_migrator.test.ts b/src/legacy/server/saved_objects/migrations/core/document_migrator.test.ts index a9df65604a9ae..778a83fa75de5 100644 --- a/src/legacy/server/saved_objects/migrations/core/document_migrator.test.ts +++ b/src/legacy/server/saved_objects/migrations/core/document_migrator.test.ts @@ -18,7 +18,6 @@ */ import _ from 'lodash'; -import sinon from 'sinon'; import { RawSavedObjectDoc } from '../../serialization'; import { DocumentMigrator } from './document_migrator'; @@ -28,7 +27,7 @@ describe('DocumentMigrator', () => { kibanaVersion: '25.2.3', migrations: {}, validateDoc: _.noop, - log: sinon.spy(), + log: jest.fn(), }; } @@ -475,7 +474,7 @@ describe('DocumentMigrator', () => { }); it('logs the document and transform that failed', () => { - const log = sinon.spy(); + const log = jest.fn(); const migrator = new DocumentMigrator({ ...testOpts(), migrations: { @@ -498,7 +497,7 @@ describe('DocumentMigrator', () => { expect('Did not throw').toEqual('But it should have!'); } catch (error) { expect(error.message).toMatch(/Dang diggity!/); - const warning = log.args.filter(([[level]]) => level === 'warning')[0][1]; + const warning = log.mock.calls.filter(([[level]]) => level === 'warning')[0][1]; expect(warning).toContain(JSON.stringify(failedDoc)); expect(warning).toContain('dog:1.2.3'); } diff --git a/src/legacy/server/saved_objects/migrations/core/elastic_index.test.ts b/src/legacy/server/saved_objects/migrations/core/elastic_index.test.ts index 9d28000affc20..34915a9218acd 100644 --- a/src/legacy/server/saved_objects/migrations/core/elastic_index.test.ts +++ b/src/legacy/server/saved_objects/migrations/core/elastic_index.test.ts @@ -18,20 +18,21 @@ */ import _ from 'lodash'; -import sinon from 'sinon'; import * as Index from './elastic_index'; describe('ElasticIndex', () => { describe('fetchInfo', () => { test('it handles 404', async () => { - const callCluster = sinon.spy(async (path: string, { ignore, index }: any) => { - expect(path).toEqual('indices.get'); - expect(ignore).toEqual([404]); - expect(index).toEqual('.kibana-test'); - return { status: 404 }; - }); + const callCluster = jest + .fn() + .mockImplementation(async (path: string, { ignore, index }: any) => { + expect(path).toEqual('indices.get'); + expect(ignore).toEqual([404]); + expect(index).toEqual('.kibana-test'); + return { status: 404 }; + }); - const info = await Index.fetchInfo(callCluster, '.kibana-test'); + const info = await Index.fetchInfo(callCluster as any, '.kibana-test'); expect(info).toEqual({ aliases: {}, exists: false, @@ -41,7 +42,7 @@ describe('ElasticIndex', () => { }); test('fails if the index doc type is unsupported', async () => { - const callCluster = sinon.spy(async (path: string, { index }: any) => { + const callCluster = jest.fn(async (path: string, { index }: any) => { return { [index]: { aliases: { foo: index }, @@ -50,13 +51,13 @@ describe('ElasticIndex', () => { }; }); - await expect(Index.fetchInfo(callCluster, '.baz')).rejects.toThrow( + await expect(Index.fetchInfo(callCluster as any, '.baz')).rejects.toThrow( /cannot be automatically migrated/ ); }); test('fails if there are multiple root types', async () => { - const callCluster = sinon.spy(async (path: string, { index }: any) => { + const callCluster = jest.fn().mockImplementation(async (path: string, { index }: any) => { return { [index]: { aliases: { foo: index }, @@ -74,7 +75,7 @@ describe('ElasticIndex', () => { }); test('decorates index info with exists and indexName', async () => { - const callCluster = sinon.spy(async (path: string, { index }: any) => { + const callCluster = jest.fn().mockImplementation(async (path: string, { index }: any) => { return { [index]: { aliases: { foo: index }, @@ -95,7 +96,7 @@ describe('ElasticIndex', () => { describe('createIndex', () => { test('calls indices.create', async () => { - const callCluster = sinon.spy(async (path: string, { body, index }: any) => { + const callCluster = jest.fn(async (path: string, { body, index }: any) => { expect(path).toEqual('indices.create'); expect(body).toEqual({ mappings: { foo: 'bar' }, @@ -104,26 +105,26 @@ describe('ElasticIndex', () => { expect(index).toEqual('.abcd'); }); - await Index.createIndex(callCluster, '.abcd', { foo: 'bar' } as any); - sinon.assert.called(callCluster); + await Index.createIndex(callCluster as any, '.abcd', { foo: 'bar' } as any); + expect(callCluster).toHaveBeenCalled(); }); }); describe('deleteIndex', () => { test('calls indices.delete', async () => { - const callCluster = sinon.spy(async (path: string, { index }: any) => { + const callCluster = jest.fn(async (path: string, { index }: any) => { expect(path).toEqual('indices.delete'); expect(index).toEqual('.lotr'); }); - await Index.deleteIndex(callCluster, '.lotr'); - sinon.assert.called(callCluster); + await Index.deleteIndex(callCluster as any, '.lotr'); + expect(callCluster).toHaveBeenCalled(); }); }); describe('claimAlias', () => { - function assertCalled(callCluster: sinon.SinonSpy) { - expect(callCluster.args.map(([path]) => path)).toEqual([ + function assertCalled(callCluster: jest.Mock) { + expect(callCluster.mock.calls.map(([path]) => path)).toEqual([ 'indices.getAlias', 'indices.updateAliases', 'indices.refresh', @@ -131,7 +132,7 @@ describe('ElasticIndex', () => { } test('handles unaliased indices', async () => { - const callCluster = sinon.spy(async (path: string, arg: any) => { + const callCluster = jest.fn(async (path: string, arg: any) => { switch (path) { case 'indices.getAlias': expect(arg.ignore).toEqual([404]); @@ -150,13 +151,13 @@ describe('ElasticIndex', () => { } }); - await Index.claimAlias(callCluster, '.hola-42', '.hola'); + await Index.claimAlias(callCluster as any, '.hola-42', '.hola'); assertCalled(callCluster); }); test('removes existing alias', async () => { - const callCluster = sinon.spy(async (path: string, arg: any) => { + const callCluster = jest.fn(async (path: string, arg: any) => { switch (path) { case 'indices.getAlias': return { '.my-fanci-index': '.muchacha' }; @@ -176,13 +177,13 @@ describe('ElasticIndex', () => { } }); - await Index.claimAlias(callCluster, '.ze-index', '.muchacha'); + await Index.claimAlias(callCluster as any, '.ze-index', '.muchacha'); assertCalled(callCluster); }); test('allows custom alias actions', async () => { - const callCluster = sinon.spy(async (path: string, arg: any) => { + const callCluster = jest.fn(async (path: string, arg: any) => { switch (path) { case 'indices.getAlias': return { '.my-fanci-index': '.muchacha' }; @@ -203,7 +204,7 @@ describe('ElasticIndex', () => { } }); - await Index.claimAlias(callCluster, '.ze-index', '.muchacha', [ + await Index.claimAlias(callCluster as any, '.ze-index', '.muchacha', [ { remove_index: { index: 'awww-snap!' } }, ]); @@ -213,7 +214,7 @@ describe('ElasticIndex', () => { describe('convertToAlias', () => { test('it creates the destination index, then reindexes to it', async () => { - const callCluster = sinon.spy(async (path: string, arg: any) => { + const callCluster = jest.fn(async (path: string, arg: any) => { switch (path) { case 'indices.create': expect(arg.body).toEqual({ @@ -266,9 +267,9 @@ describe('ElasticIndex', () => { properties: { foo: 'bar' }, }, }; - await Index.convertToAlias(callCluster, info, '.muchacha', 10); + await Index.convertToAlias(callCluster as any, info, '.muchacha', 10); - expect(callCluster.args.map(([path]) => path)).toEqual([ + expect(callCluster.mock.calls.map(([path]) => path)).toEqual([ 'indices.create', 'reindex', 'tasks.get', @@ -279,7 +280,7 @@ describe('ElasticIndex', () => { }); test('throws error if re-index task fails', async () => { - const callCluster = sinon.spy(async (path: string, arg: any) => { + const callCluster = jest.fn(async (path: string, arg: any) => { switch (path) { case 'indices.create': expect(arg.body).toEqual({ @@ -325,11 +326,11 @@ describe('ElasticIndex', () => { properties: { foo: 'bar' }, }, }; - await expect(Index.convertToAlias(callCluster, info, '.muchacha', 10)).rejects.toThrow( + await expect(Index.convertToAlias(callCluster as any, info, '.muchacha', 10)).rejects.toThrow( /Re-index failed \[search_phase_execution_exception\] all shards failed/ ); - expect(callCluster.args.map(([path]) => path)).toEqual([ + expect(callCluster.mock.calls.map(([path]) => path)).toEqual([ 'indices.create', 'reindex', 'tasks.get', @@ -340,7 +341,7 @@ describe('ElasticIndex', () => { describe('write', () => { test('writes documents in bulk to the index', async () => { const index = '.myalias'; - const callCluster = sinon.stub(); + const callCluster = jest.fn().mockResolvedValue({ items: [] }); const docs = [ { _id: 'niceguy:fredrogers', @@ -364,21 +365,19 @@ describe('ElasticIndex', () => { }, ]; - callCluster.returns( - Promise.resolve({ - items: [], - }) - ); - await Index.write(callCluster, index, docs); - sinon.assert.calledOnce(callCluster); - expect(callCluster.args[0]).toMatchSnapshot(); + expect(callCluster).toHaveBeenCalled(); + expect(callCluster.mock.calls[0]).toMatchSnapshot(); }); test('fails if any document fails', async () => { const index = '.myalias'; - const callCluster = sinon.stub(); + const callCluster = jest.fn(() => + Promise.resolve({ + items: [{ index: { error: { type: 'shazm', reason: 'dern' } } }], + }) + ); const docs = [ { _id: 'niceguy:fredrogers', @@ -391,21 +390,15 @@ describe('ElasticIndex', () => { }, ]; - callCluster.returns( - Promise.resolve({ - items: [{ index: { error: { type: 'shazm', reason: 'dern' } } }], - }) - ); - - await expect(Index.write(callCluster, index, docs)).rejects.toThrow(/dern/); - sinon.assert.calledOnce(callCluster); + await expect(Index.write(callCluster as any, index, docs)).rejects.toThrow(/dern/); + expect(callCluster).toHaveBeenCalled(); }); }); describe('reader', () => { test('returns docs in batches', async () => { const index = '.myalias'; - const callCluster = sinon.stub(); + const callCluster = jest.fn(); const batch1 = [ { @@ -430,32 +423,22 @@ describe('ElasticIndex', () => { ]; callCluster - .onCall(0) - .returns( - Promise.resolve({ - _scroll_id: 'x', - _shards: { success: 1, total: 1 }, - hits: { hits: _.cloneDeep(batch1) }, - }) - ) - .onCall(1) - .returns( - Promise.resolve({ - _scroll_id: 'y', - _shards: { success: 1, total: 1 }, - hits: { hits: _.cloneDeep(batch2) }, - }) - ) - .onCall(2) - .returns( - Promise.resolve({ - _scroll_id: 'z', - _shards: { success: 1, total: 1 }, - hits: { hits: [] }, - }) - ) - .onCall(3) - .returns(Promise.resolve()); + .mockResolvedValueOnce({ + _scroll_id: 'x', + _shards: { success: 1, total: 1 }, + hits: { hits: _.cloneDeep(batch1) }, + }) + .mockResolvedValueOnce({ + _scroll_id: 'y', + _shards: { success: 1, total: 1 }, + hits: { hits: _.cloneDeep(batch2) }, + }) + .mockResolvedValueOnce({ + _scroll_id: 'z', + _shards: { success: 1, total: 1 }, + hits: { hits: [] }, + }) + .mockResolvedValue({}); const read = Index.reader(callCluster, index, { batchSize: 100, scrollDuration: '5m' }); @@ -464,7 +447,7 @@ describe('ElasticIndex', () => { expect(await read()).toEqual([]); // Check order of calls, as well as args - expect(callCluster.args).toEqual([ + expect(callCluster.mock.calls).toEqual([ ['search', { body: { size: 100 }, index, scroll: '5m' }], ['scroll', { scroll: '5m', scrollId: 'x' }], ['scroll', { scroll: '5m', scrollId: 'y' }], @@ -474,7 +457,7 @@ describe('ElasticIndex', () => { test('returns all root-level properties', async () => { const index = '.myalias'; - const callCluster = sinon.stub(); + const callCluster = jest.fn(); const batch = [ { _id: 'such:1', @@ -488,22 +471,16 @@ describe('ElasticIndex', () => { ]; callCluster - .onCall(0) - .returns( - Promise.resolve({ - _scroll_id: 'x', - _shards: { success: 1, total: 1 }, - hits: { hits: _.cloneDeep(batch) }, - }) - ) - .onCall(1) - .returns( - Promise.resolve({ - _scroll_id: 'z', - _shards: { success: 1, total: 1 }, - hits: { hits: [] }, - }) - ); + .mockResolvedValueOnce({ + _scroll_id: 'x', + _shards: { success: 1, total: 1 }, + hits: { hits: _.cloneDeep(batch) }, + }) + .mockResolvedValue({ + _scroll_id: 'z', + _shards: { success: 1, total: 1 }, + hits: { hits: [] }, + }); const read = Index.reader(callCluster, index, { batchSize: 100, @@ -515,9 +492,9 @@ describe('ElasticIndex', () => { test('fails if not all shards were successful', async () => { const index = '.myalias'; - const callCluster = sinon.stub(); + const callCluster = jest.fn(); - callCluster.returns(Promise.resolve({ _shards: { successful: 1, total: 2 } })); + callCluster.mockResolvedValue({ _shards: { successful: 1, total: 2 } }); const read = Index.reader(callCluster, index, { batchSize: 100, @@ -529,7 +506,7 @@ describe('ElasticIndex', () => { test('handles shards not being returned', async () => { const index = '.myalias'; - const callCluster = sinon.stub(); + const callCluster = jest.fn(); const batch = [ { _id: 'such:1', @@ -543,20 +520,8 @@ describe('ElasticIndex', () => { ]; callCluster - .onCall(0) - .returns( - Promise.resolve({ - _scroll_id: 'x', - hits: { hits: _.cloneDeep(batch) }, - }) - ) - .onCall(1) - .returns( - Promise.resolve({ - _scroll_id: 'z', - hits: { hits: [] }, - }) - ); + .mockResolvedValueOnce({ _scroll_id: 'x', hits: { hits: _.cloneDeep(batch) } }) + .mockResolvedValue({ _scroll_id: 'z', hits: { hits: [] } }); const read = Index.reader(callCluster, index, { batchSize: 100, @@ -575,7 +540,7 @@ describe('ElasticIndex', () => { count, migrations, }: any) { - const callCluster = sinon.spy(async (path: string) => { + const callCluster = jest.fn(async (path: string) => { if (path === 'indices.get') { return { [index]: { mappings }, @@ -586,7 +551,7 @@ describe('ElasticIndex', () => { } throw new Error(`Unknown command ${path}.`); }); - const hasMigrations = await Index.migrationsUpToDate(callCluster, index, migrations); + const hasMigrations = await Index.migrationsUpToDate(callCluster as any, index, migrations); return { hasMigrations, callCluster }; } @@ -603,14 +568,12 @@ describe('ElasticIndex', () => { }); expect(hasMigrations).toBeFalsy(); - expect(callCluster.args).toEqual([ - [ - 'indices.get', - { - ignore: [404], - index: '.myalias', - }, - ], + expect(callCluster.mock.calls[0]).toEqual([ + 'indices.get', + { + ignore: [404], + index: '.myalias', + }, ]); }); @@ -631,8 +594,8 @@ describe('ElasticIndex', () => { }); expect(hasMigrations).toBeTruthy(); - sinon.assert.calledOnce(callCluster); - expect(callCluster.args[0][0]).toEqual('indices.get'); + expect(callCluster).toHaveBeenCalled(); + expect(callCluster.mock.calls[0][0]).toEqual('indices.get'); }); test('is true if there are no documents out of date', async () => { @@ -652,9 +615,9 @@ describe('ElasticIndex', () => { }); expect(hasMigrations).toBeTruthy(); - sinon.assert.calledTwice(callCluster); - expect(callCluster.args[0][0]).toEqual('indices.get'); - expect(callCluster.args[1][0]).toEqual('count'); + expect(callCluster).toHaveBeenCalled(); + expect(callCluster.mock.calls[0][0]).toEqual('indices.get'); + expect(callCluster.mock.calls[1][0]).toEqual('count'); }); test('is false if there are documents out of date', async () => { @@ -674,9 +637,8 @@ describe('ElasticIndex', () => { }); expect(hasMigrations).toBeFalsy(); - sinon.assert.calledTwice(callCluster); - expect(callCluster.args[0][0]).toEqual('indices.get'); - expect(callCluster.args[1][0]).toEqual('count'); + expect(callCluster.mock.calls[0][0]).toEqual('indices.get'); + expect(callCluster.mock.calls[1][0]).toEqual('count'); }); test('counts docs that are out of date', async () => { @@ -714,7 +676,7 @@ describe('ElasticIndex', () => { }; } - expect(callCluster.args[1]).toEqual([ + expect(callCluster.mock.calls[1]).toEqual([ 'count', { body: { diff --git a/src/legacy/server/saved_objects/migrations/core/index_migrator.test.ts b/src/legacy/server/saved_objects/migrations/core/index_migrator.test.ts index b163f35c80480..2f9c5d1a08672 100644 --- a/src/legacy/server/saved_objects/migrations/core/index_migrator.test.ts +++ b/src/legacy/server/saved_objects/migrations/core/index_migrator.test.ts @@ -18,25 +18,40 @@ */ import _ from 'lodash'; -import sinon from 'sinon'; import { SavedObjectsSchema } from '../../schema'; import { RawSavedObjectDoc, SavedObjectsSerializer } from '../../serialization'; -import { CallCluster } from './call_cluster'; import { IndexMigrator } from './index_migrator'; describe('IndexMigrator', () => { + let testOpts: any; + + beforeEach(() => { + testOpts = { + batchSize: 10, + callCluster: jest.fn(), + index: '.kibana', + log: jest.fn(), + mappingProperties: {}, + pollInterval: 1, + scrollDuration: '1m', + documentMigrator: { + migrationVersion: {}, + migrate: _.identity, + }, + serializer: new SavedObjectsSerializer(new SavedObjectsSchema()), + }; + }); + test('creates the index if it does not exist', async () => { - const opts = defaultOpts(); - const callCluster = clusterStub(opts); + const { callCluster } = testOpts; - opts.mappingProperties = { foo: { type: 'long' } }; + testOpts.mappingProperties = { foo: { type: 'long' } }; withIndex(callCluster, { index: { status: 404 }, alias: { status: 404 } }); - await new IndexMigrator(opts).migrate(); + await new IndexMigrator(testOpts).migrate(); - expect(ranMigration(opts)).toBeTruthy(); - sinon.assert.calledWith(callCluster, 'indices.create', { + expect(callCluster).toHaveBeenCalledWith('indices.create', { body: { mappings: { dynamic: 'strict', @@ -78,12 +93,11 @@ describe('IndexMigrator', () => { }); test('returns stats about the migration', async () => { - const opts = defaultOpts(); - const callCluster = clusterStub(opts); + const { callCluster } = testOpts; withIndex(callCluster, { index: { status: 404 }, alias: { status: 404 } }); - const result = await new IndexMigrator(opts).migrate(); + const result = await new IndexMigrator(testOpts).migrate(); expect(result).toMatchObject({ destIndex: '.kibana_1', @@ -93,8 +107,7 @@ describe('IndexMigrator', () => { }); test('fails if there are multiple root doc types', async () => { - const opts = defaultOpts(); - const callCluster = clusterStub(opts); + const { callCluster } = testOpts; withIndex(callCluster, { index: { @@ -112,14 +125,13 @@ describe('IndexMigrator', () => { }, }); - await expect(new IndexMigrator(opts).migrate()).rejects.toThrow( + await expect(new IndexMigrator(testOpts).migrate()).rejects.toThrow( /use the X-Pack upgrade assistant/ ); }); test('fails if root doc type is not "doc"', async () => { - const opts = defaultOpts(); - const callCluster = clusterStub(opts); + const { callCluster } = testOpts; withIndex(callCluster, { index: { @@ -136,16 +148,15 @@ describe('IndexMigrator', () => { }, }); - await expect(new IndexMigrator(opts).migrate()).rejects.toThrow( + await expect(new IndexMigrator(testOpts).migrate()).rejects.toThrow( /use the X-Pack upgrade assistant/ ); }); test('retains mappings from the previous index', async () => { - const opts = defaultOpts(); - const callCluster = clusterStub(opts); + const { callCluster } = testOpts; - opts.mappingProperties = { foo: { type: 'text' } }; + testOpts.mappingProperties = { foo: { type: 'text' } }; withIndex(callCluster, { index: { @@ -160,9 +171,9 @@ describe('IndexMigrator', () => { }, }); - await new IndexMigrator(opts).migrate(); + await new IndexMigrator(testOpts).migrate(); - sinon.assert.calledWith(callCluster, 'indices.create', { + expect(callCluster).toHaveBeenCalledWith('indices.create', { body: { mappings: { dynamic: 'strict', @@ -205,33 +216,31 @@ describe('IndexMigrator', () => { }); test('points the alias at the dest index', async () => { - const opts = defaultOpts(); - const callCluster = clusterStub(opts); + const { callCluster } = testOpts; withIndex(callCluster, { index: { status: 404 }, alias: { status: 404 } }); - await new IndexMigrator(opts).migrate(); + await new IndexMigrator(testOpts).migrate(); - expect(ranMigration(opts)).toBeTruthy(); - sinon.assert.calledWith(callCluster, 'indices.updateAliases', { + expect(callCluster).toHaveBeenCalledWith('indices.create', expect.any(Object)); + expect(callCluster).toHaveBeenCalledWith('indices.updateAliases', { body: { actions: [{ add: { alias: '.kibana', index: '.kibana_1' } }] }, }); }); test('removes previous indices from the alias', async () => { - const opts = defaultOpts(); - const callCluster = clusterStub(opts); + const { callCluster } = testOpts; - opts.documentMigrator.migrationVersion = { + testOpts.documentMigrator.migrationVersion = { dashboard: '2.4.5', }; withIndex(callCluster, { numOutOfDate: 1 }); - await new IndexMigrator(opts).migrate(); + await new IndexMigrator(testOpts).migrate(); - expect(ranMigration(opts)).toBeTruthy(); - sinon.assert.calledWith(callCluster, 'indices.updateAliases', { + expect(callCluster).toHaveBeenCalledWith('indices.create', expect.any(Object)); + expect(callCluster).toHaveBeenCalledWith('indices.updateAliases', { body: { actions: [ { remove: { alias: '.kibana', index: '.kibana_1' } }, @@ -243,14 +252,15 @@ describe('IndexMigrator', () => { test('transforms all docs from the original index', async () => { let count = 0; - const opts = defaultOpts(); - const callCluster = clusterStub(opts); - const migrateDoc = sinon.spy((doc: RawSavedObjectDoc) => ({ - ...doc, - attributes: { name: ++count }, - })); - - opts.documentMigrator = { + const { callCluster } = testOpts; + const migrateDoc = jest.fn((doc: RawSavedObjectDoc) => { + return { + ...doc, + attributes: { name: ++count }, + }; + }); + + testOpts.documentMigrator = { migrationVersion: { foo: '1.2.3' }, migrate: migrateDoc, }; @@ -263,57 +273,47 @@ describe('IndexMigrator', () => { ], }); - await new IndexMigrator(opts).migrate(); + await new IndexMigrator(testOpts).migrate(); expect(count).toEqual(2); - sinon.assert.calledWith(migrateDoc, { + expect(migrateDoc).toHaveBeenCalledWith({ id: '1', type: 'foo', attributes: { name: 'Bar' }, migrationVersion: {}, references: [], }); - sinon.assert.calledWith(migrateDoc, { + expect(migrateDoc).toHaveBeenCalledWith({ id: '2', type: 'foo', attributes: { name: 'Baz' }, migrationVersion: {}, references: [], }); - expect(callCluster.args.filter(([action]) => action === 'bulk').length).toEqual(2); - sinon.assert.calledWith(callCluster, 'bulk', { - body: [ - { index: { _id: 'foo:1', _index: '.kibana_2' } }, - { foo: { name: 1 }, type: 'foo', migrationVersion: {}, references: [] }, - ], - }); - sinon.assert.calledWith(callCluster, 'bulk', { - body: [ - { index: { _id: 'foo:2', _index: '.kibana_2' } }, - { foo: { name: 2 }, type: 'foo', migrationVersion: {}, references: [] }, - ], - }); + const bulkCalls = callCluster.mock.calls.filter(([action]: any) => action === 'bulk'); + expect(bulkCalls.length).toEqual(2); + expect(bulkCalls[0]).toEqual([ + 'bulk', + { + body: [ + { index: { _id: 'foo:1', _index: '.kibana_2' } }, + { foo: { name: 1 }, type: 'foo', migrationVersion: {}, references: [] }, + ], + }, + ]); + expect(bulkCalls[1]).toEqual([ + 'bulk', + { + body: [ + { index: { _id: 'foo:2', _index: '.kibana_2' } }, + { foo: { name: 2 }, type: 'foo', migrationVersion: {}, references: [] }, + ], + }, + ]); }); }); -function defaultOpts() { - return { - batchSize: 10, - callCluster: sinon.stub(), - index: '.kibana', - log: sinon.stub(), - mappingProperties: {}, - pollInterval: 1, - scrollDuration: '1m', - documentMigrator: { - migrationVersion: {}, - migrate: _.identity, - }, - serializer: new SavedObjectsSerializer(new SavedObjectsSchema()), - }; -} - -function withIndex(callCluster: sinon.SinonStub, opts: any = {}) { +function withIndex(callCluster: jest.Mock, opts: any = {}) { const defaultIndex = { '.kibana_1': { aliases: { '.kibana': {} }, @@ -343,36 +343,28 @@ function withIndex(callCluster: sinon.SinonStub, opts: any = {}) { hits: docs[i] || [], }, }); - callCluster.withArgs('indices.get').returns(Promise.resolve(index)); - callCluster.withArgs('indices.getAlias').returns(Promise.resolve(alias)); - callCluster - .withArgs('reindex') - .returns(Promise.resolve({ task: 'zeid', _shards: { successful: 1, total: 1 } })); - callCluster.withArgs('tasks.get').returns(Promise.resolve({ completed: true })); - callCluster.withArgs('search').returns(searchResult(0)); - - _.range(1, docs.length).forEach(i => { - callCluster - .withArgs('scroll') - .onCall(i - 1) - .returns(searchResult(i)); - }); - callCluster - .withArgs('scroll') - .onCall(docs.length - 1) - .returns(searchResult(docs.length)); - - callCluster.withArgs('bulk').returns(Promise.resolve({ items: [] })); - callCluster - .withArgs('count') - .returns(Promise.resolve({ count: numOutOfDate, _shards: { successful: 1, total: 1 } })); -} - -function clusterStub(opts: { callCluster: CallCluster }) { - return opts.callCluster as sinon.SinonStub; -} - -function ranMigration(opts: { callCluster: CallCluster }) { - return clusterStub(opts).calledWith('indices.create', sinon.match.any); + let scrollCallCounter = 1; + + callCluster.mockImplementation(method => { + if (method === 'indices.get') { + return Promise.resolve(index); + } else if (method === 'indices.getAlias') { + return Promise.resolve(alias); + } else if (method === 'reindex') { + return Promise.resolve({ task: 'zeid', _shards: { successful: 1, total: 1 } }); + } else if (method === 'tasks.get') { + return Promise.resolve({ completed: true }); + } else if (method === 'search') { + return searchResult(0); + } else if (method === 'bulk') { + return Promise.resolve({ items: [] }); + } else if (method === 'count') { + return Promise.resolve({ count: numOutOfDate, _shards: { successful: 1, total: 1 } }); + } else if (method === 'scroll' && scrollCallCounter <= docs.length) { + const result = searchResult(scrollCallCounter); + scrollCallCounter++; + return result; + } + }); } diff --git a/src/legacy/server/saved_objects/migrations/core/migrate_raw_docs.test.ts b/src/legacy/server/saved_objects/migrations/core/migrate_raw_docs.test.ts index 26ccb4085e2a9..aa208a23954f0 100644 --- a/src/legacy/server/saved_objects/migrations/core/migrate_raw_docs.test.ts +++ b/src/legacy/server/saved_objects/migrations/core/migrate_raw_docs.test.ts @@ -18,14 +18,13 @@ */ import _ from 'lodash'; -import sinon from 'sinon'; import { SavedObjectsSchema } from '../../schema'; import { SavedObjectsSerializer } from '../../serialization'; import { migrateRawDocs } from './migrate_raw_docs'; describe('migrateRawDocs', () => { test('converts raw docs to saved objects', async () => { - const transform = sinon.spy((doc: any) => _.set(doc, 'attributes.name', 'HOI!')); + const transform = jest.fn((doc: any) => _.set(doc, 'attributes.name', 'HOI!')); const result = migrateRawDocs(new SavedObjectsSerializer(new SavedObjectsSchema()), transform, [ { _id: 'a:b', _source: { type: 'a', a: { name: 'AAA' } } }, { _id: 'c:d', _source: { type: 'c', c: { name: 'DDD' } } }, @@ -42,11 +41,13 @@ describe('migrateRawDocs', () => { }, ]); - sinon.assert.calledTwice(transform); + expect(transform).toHaveBeenCalled(); }); test('passes invalid docs through untouched', async () => { - const transform = sinon.spy((doc: any) => _.set(_.cloneDeep(doc), 'attributes.name', 'TADA')); + const transform = jest.fn((doc: any) => + _.set(_.cloneDeep(doc), 'attributes.name', 'TADA') + ); const result = migrateRawDocs(new SavedObjectsSerializer(new SavedObjectsSchema()), transform, [ { _id: 'foo:b', _source: { type: 'a', a: { name: 'AAA' } } }, { _id: 'c:d', _source: { type: 'c', c: { name: 'DDD' } } }, @@ -60,7 +61,7 @@ describe('migrateRawDocs', () => { }, ]); - expect(transform.args).toEqual([ + expect(transform.mock.calls).toEqual([ [ { id: 'd', diff --git a/src/legacy/server/saved_objects/migrations/core/migration_coordinator.test.ts b/src/legacy/server/saved_objects/migrations/core/migration_coordinator.test.ts index d010ba4913db6..906a7311a0f64 100644 --- a/src/legacy/server/saved_objects/migrations/core/migration_coordinator.test.ts +++ b/src/legacy/server/saved_objects/migrations/core/migration_coordinator.test.ts @@ -18,23 +18,23 @@ */ import _ from 'lodash'; -import sinon from 'sinon'; import { coordinateMigration } from './migration_coordinator'; describe('coordinateMigration', () => { + const log = { + debug: jest.fn(), + warning: jest.fn(), + info: jest.fn(), + }; + test('waits for isMigrated, if there is an index conflict', async () => { - const log = logStub(); const pollInterval = 1; - const runMigration = sinon.spy(() => { + const runMigration = jest.fn(() => { throw { body: { error: { index: '.foo', type: 'resource_already_exists_exception' } } }; }); - const isMigrated = sinon.stub(); + const isMigrated = jest.fn(); - isMigrated - .onFirstCall() - .returns(Promise.resolve(false)) - .onSecondCall() - .returns(Promise.resolve(true)); + isMigrated.mockResolvedValueOnce(false).mockResolvedValueOnce(true); await coordinateMigration({ log, @@ -43,17 +43,16 @@ describe('coordinateMigration', () => { isMigrated, }); - sinon.assert.calledOnce(runMigration); - sinon.assert.calledTwice(isMigrated); - const warnings = log.warning.args.filter((msg: any) => /deleting index \.foo/.test(msg)); + expect(runMigration).toHaveBeenCalledTimes(1); + expect(isMigrated).toHaveBeenCalledTimes(2); + const warnings = log.warning.mock.calls.filter((msg: any) => /deleting index \.foo/.test(msg)); expect(warnings.length).toEqual(1); }); test('does not poll if the runMigration succeeds', async () => { - const log = logStub(); const pollInterval = 1; - const runMigration = sinon.spy(() => Promise.resolve()); - const isMigrated = sinon.spy(() => Promise.resolve(true)); + const runMigration = jest.fn(() => Promise.resolve()); + const isMigrated = jest.fn(() => Promise.resolve(true)); await coordinateMigration({ log, @@ -61,16 +60,15 @@ describe('coordinateMigration', () => { pollInterval, isMigrated, }); - sinon.assert.notCalled(isMigrated); + expect(isMigrated).not.toHaveBeenCalled(); }); test('does not swallow exceptions', async () => { - const log = logStub(); const pollInterval = 1; - const runMigration = sinon.spy(() => { + const runMigration = jest.fn(() => { throw new Error('Doh'); }); - const isMigrated = sinon.spy(() => Promise.resolve(true)); + const isMigrated = jest.fn(() => Promise.resolve(true)); await expect( coordinateMigration({ @@ -80,13 +78,6 @@ describe('coordinateMigration', () => { isMigrated, }) ).rejects.toThrow(/Doh/); - sinon.assert.notCalled(isMigrated); + expect(isMigrated).not.toHaveBeenCalled(); }); }); - -function logStub(): any { - return sinon.stub({ - debug: _.noop, - warning: _.noop, - }); -} diff --git a/src/legacy/server/saved_objects/migrations/kibana/kibana_migrator.test.ts b/src/legacy/server/saved_objects/migrations/kibana/kibana_migrator.test.ts index e9c37fb856266..e81c04b7a35b3 100644 --- a/src/legacy/server/saved_objects/migrations/kibana/kibana_migrator.test.ts +++ b/src/legacy/server/saved_objects/migrations/kibana/kibana_migrator.test.ts @@ -18,7 +18,6 @@ */ import _ from 'lodash'; -import sinon from 'sinon'; import { KbnServer, KibanaMigrator } from './kibana_migrator'; describe('KibanaMigrator', () => { @@ -67,16 +66,16 @@ describe('KibanaMigrator', () => { it('waits for kbnServer.ready and elasticsearch.ready before attempting migrations', async () => { const { kbnServer } = mockKbnServer(); - const clusterStub = sinon.stub(); - const waitUntilReady = sinon.spy(async () => undefined); - - clusterStub.throws(new Error('Doh!')); + const clusterStub = jest.fn(() => { + throw new Error('Doh!'); + }); + const waitUntilReady = jest.fn(async () => undefined); kbnServer.server.plugins.elasticsearch = { waitUntilReady, getCluster() { - sinon.assert.calledOnce(kbnServer.ready as any); - sinon.assert.calledOnce(waitUntilReady); + expect(kbnServer.ready as any).toHaveBeenCalledTimes(1); + expect(waitUntilReady).toHaveBeenCalledTimes(1); return { callWithInternalUser: clusterStub, @@ -90,10 +89,10 @@ describe('KibanaMigrator', () => { }); function mockKbnServer({ configValues }: { configValues?: any } = {}) { - const callCluster = sinon.stub(); + const callCluster = jest.fn(); const kbnServer: KbnServer = { version: '8.2.3', - ready: sinon.spy(async () => undefined), + ready: jest.fn(async () => undefined), uiExports: { savedObjectValidations: {}, savedObjectMigrations: {}, diff --git a/src/legacy/server/saved_objects/routes/bulk_create.test.js b/src/legacy/server/saved_objects/routes/bulk_create.test.js index ae7cb92733c53..abfacfcbc4448 100644 --- a/src/legacy/server/saved_objects/routes/bulk_create.test.js +++ b/src/legacy/server/saved_objects/routes/bulk_create.test.js @@ -17,15 +17,15 @@ * under the License. */ -import sinon from 'sinon'; import { createBulkCreateRoute } from './bulk_create'; import { MockServer } from './_mock_server'; describe('POST /api/saved_objects/_bulk_create', () => { - const savedObjectsClient = { bulkCreate: sinon.stub().returns('') }; + const savedObjectsClient = { bulkCreate: jest.fn() }; let server; beforeEach(() => { + savedObjectsClient.bulkCreate.mockImplementation(() => Promise.resolve('')); server = new MockServer(); const prereqs = { @@ -41,7 +41,7 @@ describe('POST /api/saved_objects/_bulk_create', () => { }); afterEach(() => { - savedObjectsClient.bulkCreate.resetHistory(); + savedObjectsClient.bulkCreate.mockReset(); }); it('formats successful response', async () => { @@ -67,7 +67,7 @@ describe('POST /api/saved_objects/_bulk_create', () => { }] }; - savedObjectsClient.bulkCreate.returns(Promise.resolve(clientResponse)); + savedObjectsClient.bulkCreate.mockImplementation(() => Promise.resolve(clientResponse)); const { payload, statusCode } = await server.inject(request); const response = JSON.parse(payload); @@ -100,9 +100,9 @@ describe('POST /api/saved_objects/_bulk_create', () => { }; await server.inject(request); - expect(savedObjectsClient.bulkCreate.calledOnce).toBe(true); + expect(savedObjectsClient.bulkCreate).toHaveBeenCalled(); - const args = savedObjectsClient.bulkCreate.getCall(0).args; + const args = savedObjectsClient.bulkCreate.mock.calls[0]; expect(args[0]).toEqual(docs); }); @@ -114,15 +114,15 @@ describe('POST /api/saved_objects/_bulk_create', () => { id: 'abc1234', type: 'index-pattern', attributes: { - title: 'bar', + title: 'foo', }, references: [], }] }); - expect(savedObjectsClient.bulkCreate.calledOnce).toBe(true); + expect(savedObjectsClient.bulkCreate).toHaveBeenCalled(); - const args = savedObjectsClient.bulkCreate.getCall(0).args; + const args = savedObjectsClient.bulkCreate.mock.calls[0]; expect(args[1]).toEqual({ overwrite: true }); }); }); diff --git a/src/legacy/server/saved_objects/routes/bulk_get.test.js b/src/legacy/server/saved_objects/routes/bulk_get.test.js index ac2956eb0dffc..0b5141fe403d8 100644 --- a/src/legacy/server/saved_objects/routes/bulk_get.test.js +++ b/src/legacy/server/saved_objects/routes/bulk_get.test.js @@ -17,17 +17,16 @@ * under the License. */ -import sinon from 'sinon'; import { createBulkGetRoute } from './bulk_get'; import { MockServer } from './_mock_server'; describe('POST /api/saved_objects/_bulk_get', () => { - const savedObjectsClient = { bulkGet: sinon.stub().returns('') }; + const savedObjectsClient = { bulkGet: jest.fn() }; let server; beforeEach(() => { + savedObjectsClient.bulkGet.mockImplementation(() => Promise.resolve('')); server = new MockServer(); - const prereqs = { getSavedObjectsClient: { assign: 'savedObjectsClient', @@ -41,7 +40,7 @@ describe('POST /api/saved_objects/_bulk_get', () => { }); afterEach(() => { - savedObjectsClient.bulkGet.resetHistory(); + savedObjectsClient.bulkGet.mockReset(); }); it('formats successful response', async () => { @@ -64,7 +63,7 @@ describe('POST /api/saved_objects/_bulk_get', () => { }] }; - savedObjectsClient.bulkGet.returns(Promise.resolve(clientResponse)); + savedObjectsClient.bulkGet.mockImplementation(() => Promise.resolve(clientResponse)); const { payload, statusCode } = await server.inject(request); const response = JSON.parse(payload); @@ -86,9 +85,7 @@ describe('POST /api/saved_objects/_bulk_get', () => { }; await server.inject(request); - expect(savedObjectsClient.bulkGet.calledOnce).toBe(true); - const args = savedObjectsClient.bulkGet.getCall(0).args; - expect(args[0]).toEqual(docs); + expect(savedObjectsClient.bulkGet).toHaveBeenCalledWith(docs); }); }); diff --git a/src/legacy/server/saved_objects/routes/create.test.js b/src/legacy/server/saved_objects/routes/create.test.js index 4e35e2e3b38d4..c50b5edb8a0f1 100644 --- a/src/legacy/server/saved_objects/routes/create.test.js +++ b/src/legacy/server/saved_objects/routes/create.test.js @@ -17,15 +17,15 @@ * under the License. */ -import sinon from 'sinon'; import { createCreateRoute } from './create'; import { MockServer } from './_mock_server'; describe('POST /api/saved_objects/{type}', () => { - const savedObjectsClient = { create: sinon.stub().returns('') }; + const savedObjectsClient = { create: jest.fn() }; let server; beforeEach(() => { + savedObjectsClient.create.mockImplementation(() => Promise.resolve('')); server = new MockServer(); const prereqs = { @@ -41,7 +41,7 @@ describe('POST /api/saved_objects/{type}', () => { }); afterEach(() => { - savedObjectsClient.create.resetHistory(); + savedObjectsClient.create.mockReset(); }); it('formats successful response', async () => { @@ -54,6 +54,7 @@ describe('POST /api/saved_objects/{type}', () => { } } }; + const clientResponse = { type: 'index-pattern', id: 'logstash-*', @@ -61,7 +62,7 @@ describe('POST /api/saved_objects/{type}', () => { references: [], }; - savedObjectsClient.create.returns(Promise.resolve(clientResponse)); + savedObjectsClient.create.mockImplementation(() => Promise.resolve(clientResponse)); const { payload, statusCode } = await server.inject(request); const response = JSON.parse(payload); @@ -98,13 +99,13 @@ describe('POST /api/saved_objects/{type}', () => { }; await server.inject(request); - expect(savedObjectsClient.create.calledOnce).toBe(true); - - const args = savedObjectsClient.create.getCall(0).args; - const options = { overwrite: false, id: undefined, migrationVersion: undefined, references: [] }; - const attributes = { title: 'Testing' }; + expect(savedObjectsClient.create).toHaveBeenCalled(); - expect(args).toEqual(['index-pattern', attributes, options]); + expect(savedObjectsClient.create).toHaveBeenCalledWith( + 'index-pattern', + { title: 'Testing' }, + { overwrite: false, id: undefined, migrationVersion: undefined, references: [] } + ); }); it('can specify an id', async () => { @@ -119,9 +120,9 @@ describe('POST /api/saved_objects/{type}', () => { }; await server.inject(request); - expect(savedObjectsClient.create.calledOnce).toBe(true); + expect(savedObjectsClient.create).toHaveBeenCalled(); - const args = savedObjectsClient.create.getCall(0).args; + const args = savedObjectsClient.create.mock.calls[0]; const options = { overwrite: false, id: 'logstash-*', references: [] }; const attributes = { title: 'Testing' }; diff --git a/src/legacy/server/saved_objects/routes/delete.test.js b/src/legacy/server/saved_objects/routes/delete.test.js index ef130048f3c56..d64167a0af590 100644 --- a/src/legacy/server/saved_objects/routes/delete.test.js +++ b/src/legacy/server/saved_objects/routes/delete.test.js @@ -17,15 +17,15 @@ * under the License. */ -import sinon from 'sinon'; import { createDeleteRoute } from './delete'; import { MockServer } from './_mock_server'; describe('DELETE /api/saved_objects/{type}/{id}', () => { - const savedObjectsClient = { delete: sinon.stub() }; + const savedObjectsClient = { delete: jest.fn() }; let server; beforeEach(() => { + savedObjectsClient.delete.mockImplementation(() => Promise.resolve('{}')); server = new MockServer(); const prereqs = { @@ -41,7 +41,7 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => { }); afterEach(() => { - savedObjectsClient.delete.resetHistory(); + savedObjectsClient.delete.mockReset(); }); it('formats successful response', async () => { @@ -49,15 +49,12 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => { method: 'DELETE', url: '/api/saved_objects/index-pattern/logstash-*' }; - const clientResponse = true; - - savedObjectsClient.delete.returns(Promise.resolve(clientResponse)); const { payload, statusCode } = await server.inject(request); const response = JSON.parse(payload); expect(statusCode).toBe(200); - expect(response).toEqual(clientResponse); + expect(response).toEqual({}); }); it('calls upon savedObjectClient.delete', async () => { @@ -67,9 +64,6 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => { }; await server.inject(request); - expect(savedObjectsClient.delete.calledOnce).toBe(true); - - const args = savedObjectsClient.delete.getCall(0).args; - expect(args).toEqual(['index-pattern', 'logstash-*']); + expect(savedObjectsClient.delete).toHaveBeenCalledWith('index-pattern', 'logstash-*'); }); }); diff --git a/src/legacy/server/saved_objects/routes/find.test.js b/src/legacy/server/saved_objects/routes/find.test.js index d11ac8f00cb54..4657c5f732ddd 100644 --- a/src/legacy/server/saved_objects/routes/find.test.js +++ b/src/legacy/server/saved_objects/routes/find.test.js @@ -17,15 +17,15 @@ * under the License. */ -import sinon from 'sinon'; import { createFindRoute } from './find'; import { MockServer } from './_mock_server'; describe('GET /api/saved_objects/_find', () => { - const savedObjectsClient = { find: sinon.stub().returns('') }; + const savedObjectsClient = { find: jest.fn() }; let server; beforeEach(() => { + savedObjectsClient.find.mockImplementation(() => Promise.resolve('')); server = new MockServer(); const prereqs = { @@ -41,7 +41,7 @@ describe('GET /api/saved_objects/_find', () => { }); afterEach(() => { - savedObjectsClient.find.resetHistory(); + savedObjectsClient.find.mockReset(); }); it('returns with status 400 when type is missing', async () => { @@ -87,7 +87,7 @@ describe('GET /api/saved_objects/_find', () => { ] }; - savedObjectsClient.find.returns(Promise.resolve(clientResponse)); + savedObjectsClient.find.mockImplementation(() => Promise.resolve(clientResponse)); const { payload, statusCode } = await server.inject(request); const response = JSON.parse(payload); @@ -104,9 +104,9 @@ describe('GET /api/saved_objects/_find', () => { await server.inject(request); - expect(savedObjectsClient.find.calledOnce).toBe(true); + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - const options = savedObjectsClient.find.getCall(0).args[0]; + const options = savedObjectsClient.find.mock.calls[0][0]; expect(options).toEqual({ perPage: 20, page: 1, type: ['foo', 'bar'], defaultSearchOperator: 'OR' }); }); @@ -118,9 +118,9 @@ describe('GET /api/saved_objects/_find', () => { await server.inject(request); - expect(savedObjectsClient.find.calledOnce).toBe(true); + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - const options = savedObjectsClient.find.getCall(0).args[0]; + const options = savedObjectsClient.find.mock.calls[0][0]; expect(options).toEqual({ perPage: 10, page: 50, type: ['foo'], defaultSearchOperator: 'OR' }); }); @@ -132,9 +132,9 @@ describe('GET /api/saved_objects/_find', () => { await server.inject(request); - expect(savedObjectsClient.find.calledOnce).toBe(true); + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - const options = savedObjectsClient.find.getCall(0).args[0]; + const options = savedObjectsClient.find.mock.calls[0][0]; expect(options).toEqual({ perPage: 20, page: 1, searchFields: ['title'], type: ['foo'], defaultSearchOperator: 'OR' }); }); @@ -146,9 +146,9 @@ describe('GET /api/saved_objects/_find', () => { await server.inject(request); - expect(savedObjectsClient.find.calledOnce).toBe(true); + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - const options = savedObjectsClient.find.getCall(0).args[0]; + const options = savedObjectsClient.find.mock.calls[0][0]; expect(options).toEqual({ perPage: 20, page: 1, fields: ['title'], type: ['foo'], defaultSearchOperator: 'OR' }); }); @@ -160,9 +160,9 @@ describe('GET /api/saved_objects/_find', () => { await server.inject(request); - expect(savedObjectsClient.find.calledOnce).toBe(true); + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - const options = savedObjectsClient.find.getCall(0).args[0]; + const options = savedObjectsClient.find.mock.calls[0][0]; expect(options).toEqual({ perPage: 20, page: 1, fields: ['title', 'description'], type: ['foo'], defaultSearchOperator: 'OR' }); @@ -176,9 +176,9 @@ describe('GET /api/saved_objects/_find', () => { await server.inject(request); - expect(savedObjectsClient.find.calledOnce).toBe(true); + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - const options = savedObjectsClient.find.getCall(0).args[0]; + const options = savedObjectsClient.find.mock.calls[0][0]; expect(options).toEqual({ perPage: 20, page: 1, type: ['index-pattern'], defaultSearchOperator: 'OR' }); }); @@ -190,9 +190,9 @@ describe('GET /api/saved_objects/_find', () => { await server.inject(request); - expect(savedObjectsClient.find.calledOnce).toBe(true); + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); - const options = savedObjectsClient.find.getCall(0).args[0]; + const options = savedObjectsClient.find.mock.calls[0][0]; expect(options).toEqual({ perPage: 20, page: 1, type: ['index-pattern', 'visualization'], defaultSearchOperator: 'OR' }); }); }); diff --git a/src/legacy/server/saved_objects/routes/get.test.js b/src/legacy/server/saved_objects/routes/get.test.js index d139d54ef0ecf..be5d1be1733e5 100644 --- a/src/legacy/server/saved_objects/routes/get.test.js +++ b/src/legacy/server/saved_objects/routes/get.test.js @@ -17,15 +17,15 @@ * under the License. */ -import sinon from 'sinon'; import { createGetRoute } from './get'; import { MockServer } from './_mock_server'; describe('GET /api/saved_objects/{type}/{id}', () => { - const savedObjectsClient = { get: sinon.stub().returns('') }; + const savedObjectsClient = { get: jest.fn() }; let server; beforeEach(() => { + savedObjectsClient.get.mockImplementation(() => Promise.resolve(true)); server = new MockServer(); const prereqs = { @@ -41,7 +41,7 @@ describe('GET /api/saved_objects/{type}/{id}', () => { }); afterEach(() => { - savedObjectsClient.get.resetHistory(); + savedObjectsClient.get.mockReset(); }); it('formats successful response', async () => { @@ -57,7 +57,7 @@ describe('GET /api/saved_objects/{type}/{id}', () => { references: [], }; - savedObjectsClient.get.returns(Promise.resolve(clientResponse)); + savedObjectsClient.get.mockImplementation(() => Promise.resolve(clientResponse)); const { payload, statusCode } = await server.inject(request); const response = JSON.parse(payload); @@ -73,9 +73,9 @@ describe('GET /api/saved_objects/{type}/{id}', () => { }; await server.inject(request); - expect(savedObjectsClient.get.calledOnce).toBe(true); + expect(savedObjectsClient.get).toHaveBeenCalled(); - const args = savedObjectsClient.get.getCall(0).args; + const args = savedObjectsClient.get.mock.calls[0]; expect(args).toEqual(['index-pattern', 'logstash-*']); }); }); diff --git a/src/legacy/server/saved_objects/routes/update.test.js b/src/legacy/server/saved_objects/routes/update.test.js index fc76815c95c08..76934b8273959 100644 --- a/src/legacy/server/saved_objects/routes/update.test.js +++ b/src/legacy/server/saved_objects/routes/update.test.js @@ -17,16 +17,17 @@ * under the License. */ -import sinon from 'sinon'; import { createUpdateRoute } from './update'; import { MockServer } from './_mock_server'; describe('PUT /api/saved_objects/{type}/{id?}', () => { - const savedObjectsClient = { update: sinon.stub().returns('') }; + + const savedObjectsClient = { update: jest.fn() }; let server; beforeEach(() => { server = new MockServer(); + savedObjectsClient.update.mockImplementation(() => Promise.resolve(true)); const prereqs = { getSavedObjectsClient: { @@ -41,7 +42,7 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => { }); afterEach(() => { - savedObjectsClient.update.resetHistory(); + savedObjectsClient.update.mockReset(); }); it('formats successful response', async () => { @@ -56,31 +57,40 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => { } }; - savedObjectsClient.update.returns(Promise.resolve(true)); + const clientResponse = { + id: 'logstash-*', + title: 'logstash-*', + timeFieldName: '@timestamp', + notExpandable: true, + references: [], + }; + + savedObjectsClient.update.mockImplementation(() => Promise.resolve(clientResponse)); const { payload, statusCode } = await server.inject(request); const response = JSON.parse(payload); expect(statusCode).toBe(200); - expect(response).toEqual(true); + expect(response).toEqual(clientResponse); }); it('calls upon savedObjectClient.update', async () => { - const attributes = { title: 'Testing' }; - const options = { version: 'foo', references: [] }; const request = { method: 'PUT', url: '/api/saved_objects/index-pattern/logstash-*', payload: { - attributes, - version: options.version + attributes: { title: 'Testing' }, + version: 'foo', } }; await server.inject(request); - expect(savedObjectsClient.update.calledOnce).toBe(true); - const args = savedObjectsClient.update.getCall(0).args; - expect(args).toEqual(['index-pattern', 'logstash-*', attributes, options]); + expect(savedObjectsClient.update).toHaveBeenCalledWith( + 'index-pattern', + 'logstash-*', + { title: 'Testing' }, + { version: 'foo', references: [] } + ); }); }); diff --git a/src/legacy/server/saved_objects/saved_objects_mixin.test.js b/src/legacy/server/saved_objects/saved_objects_mixin.test.js index 98ba0cab50f39..eece1a523e56a 100644 --- a/src/legacy/server/saved_objects/saved_objects_mixin.test.js +++ b/src/legacy/server/saved_objects/saved_objects_mixin.test.js @@ -18,20 +18,19 @@ */ import { savedObjectsMixin } from './saved_objects_mixin'; -import sinon from 'sinon'; describe('Saved Objects Mixin', () => { let mockKbnServer; let mockServer; - const mockCallCluster = sinon.spy(); - const stubCallCluster = sinon.stub(); - const stubConfig = sinon.stub(); + const mockCallCluster = jest.fn(); + const stubCallCluster = jest.fn(); + const stubConfig = jest.fn(); beforeEach(() => { mockServer = { - log: sinon.spy(), - route: sinon.spy(), - decorate: sinon.spy(), + log: jest.fn(), + route: jest.fn(), + decorate: jest.fn(), config: () => { return { get: stubConfig, @@ -45,7 +44,7 @@ describe('Saved Objects Mixin', () => { callWithInternalUser: stubCallCluster, }; }, - waitUntilReady: sinon.spy(), + waitUntilReady: jest.fn(), }, }, }; @@ -89,45 +88,45 @@ describe('Saved Objects Mixin', () => { it('should not try to create anything', () => { mockKbnServer.pluginSpecs.some = () => false; savedObjectsMixin(mockKbnServer, mockServer); - mockServer.log.calledWithMatch(sinon.match.array, sinon.match.string); - mockServer.decorate.calledWithMatch('server', 'kibanaMigrator', sinon.match.object); - expect(mockServer.decorate.callCount).toBe(1); - expect(mockServer.route.callCount).toBe(0); + expect(mockServer.log).toHaveBeenCalledWith(expect.any(Array), expect.any(String)); + expect(mockServer.decorate).toHaveBeenCalledWith('server', 'kibanaMigrator', expect.any(Object)); + expect(mockServer.decorate).toHaveBeenCalledTimes(1); + expect(mockServer.route).not.toHaveBeenCalled(); }); }); describe('Routes', () => { it('should create 7 routes', () => { savedObjectsMixin(mockKbnServer, mockServer); - expect(mockServer.route.callCount).toBe(7); + expect(mockServer.route).toHaveBeenCalledTimes(7); }); it('should add POST /api/saved_objects/_bulk_create', () => { savedObjectsMixin(mockKbnServer, mockServer); - expect(mockServer.route.calledWithMatch(sinon.match({ path: '/api/saved_objects/_bulk_create', method: 'POST' }))).toBeTruthy(); + expect(mockServer.route).toHaveBeenCalledWith(expect.objectContaining({ path: '/api/saved_objects/_bulk_create', method: 'POST' })); }); it('should add POST /api/saved_objects/_bulk_get', () => { savedObjectsMixin(mockKbnServer, mockServer); - expect(mockServer.route.calledWithMatch(sinon.match({ path: '/api/saved_objects/_bulk_get', method: 'POST' }))).toBeTruthy(); + expect(mockServer.route).toHaveBeenCalledWith(expect.objectContaining({ path: '/api/saved_objects/_bulk_get', method: 'POST' })); }); it('should add POST /api/saved_objects/{type}/{id?}', () => { savedObjectsMixin(mockKbnServer, mockServer); - expect(mockServer.route.calledWithMatch(sinon.match({ path: '/api/saved_objects/{type}/{id?}', method: 'POST' }))).toBeTruthy(); + expect(mockServer.route).toHaveBeenCalledWith(expect.objectContaining({ path: '/api/saved_objects/{type}/{id?}', method: 'POST' })); }); it('should add DELETE /api/saved_objects/{type}/{id}', () => { savedObjectsMixin(mockKbnServer, mockServer); - expect(mockServer.route.calledWithMatch(sinon.match({ path: '/api/saved_objects/{type}/{id}', method: 'DELETE' }))).toBeTruthy(); + expect(mockServer.route).toHaveBeenCalledWith(expect.objectContaining({ path: '/api/saved_objects/{type}/{id}', method: 'DELETE' })); }); it('should add GET /api/saved_objects/_find', () => { savedObjectsMixin(mockKbnServer, mockServer); - expect(mockServer.route.calledWithMatch(sinon.match({ path: '/api/saved_objects/_find', method: 'GET' }))).toBeTruthy(); + expect(mockServer.route).toHaveBeenCalledWith(expect.objectContaining({ path: '/api/saved_objects/_find', method: 'GET' })); }); it('should add GET /api/saved_objects/{type}/{id}', () => { savedObjectsMixin(mockKbnServer, mockServer); - expect(mockServer.route.calledWithMatch(sinon.match({ path: '/api/saved_objects/{type}/{id}', method: 'GET' }))).toBeTruthy(); + expect(mockServer.route).toHaveBeenCalledWith(expect.objectContaining({ path: '/api/saved_objects/{type}/{id}', method: 'GET' })); }); it('should add PUT /api/saved_objects/{type}/{id}', () => { savedObjectsMixin(mockKbnServer, mockServer); - expect(mockServer.route.calledWithMatch(sinon.match({ path: '/api/saved_objects/{type}/{id}', method: 'PUT' }))).toBeTruthy(); + expect(mockServer.route).toHaveBeenCalledWith(expect.objectContaining({ path: '/api/saved_objects/{type}/{id}', method: 'PUT' })); }); }); @@ -136,13 +135,8 @@ describe('Saved Objects Mixin', () => { beforeEach(() => { savedObjectsMixin(mockKbnServer, mockServer); - for(let n = 0; n < mockServer.decorate.callCount; ++n) { - const decorateCall = mockServer.decorate.getCall(n); - if(decorateCall.calledWithMatch('server', 'savedObjects', sinon.match({}))) { - service = decorateCall.args[2]; - break; - } - } + const call = mockServer.decorate.mock.calls.filter(([objName, methodName]) => objName === 'server' && methodName === 'savedObjects'); + service = call[0][2]; }); it('should return all but hidden types', () => { @@ -150,7 +144,7 @@ describe('Saved Objects Mixin', () => { expect(service.types).toEqual(['config', 'testtype']); }); - const mockCallEs = sinon.spy(); + const mockCallEs = jest.fn(); describe('repository creation', () => { it('should not allow a repository with an undefined type', () => { expect(() => { @@ -208,13 +202,19 @@ describe('Saved Objects Mixin', () => { }); it('should call underlining callCluster', async () => { - stubCallCluster.withArgs('indices.get').returns({ status: 404 }); - stubCallCluster.withArgs('indices.getAlias').returns({ status: 404 }); - stubCallCluster.withArgs('cat.templates').returns([]); - stubConfig.withArgs('kibana.index').returns('kibana-index'); + stubCallCluster.mockImplementation((method) => { + if (method === 'indices.get') { + return { status: 404 }; + } else if (method === 'indices.getAlias') { + return { status: 404 }; + } else if (method === 'cat.templates') { + return []; + } + }); + stubConfig.mockImplementation(() => 'kibana-index'); const client = await service.getScopedSavedObjectsClient(); await client.create('testtype'); - expect(stubCallCluster.calledWithMatch('create', sinon.match.object)).toBeTruthy(); + expect(stubCallCluster).toHaveBeenCalled(); }); }); @@ -223,13 +223,10 @@ describe('Saved Objects Mixin', () => { beforeEach(() => { savedObjectsMixin(mockKbnServer, mockServer); - for(let n = 0; n < mockServer.decorate.callCount; ++n) { - const decorateCall = mockServer.decorate.getCall(n); - if(decorateCall.calledWithMatch('request', 'getSavedObjectsClient', sinon.match.func)) { - getSavedObjectsClient = decorateCall.args[2]; - break; - } - } + const call = mockServer.decorate.mock.calls.filter( + ([objName, methodName]) => objName === 'request' && methodName === 'getSavedObjectsClient' + ); + getSavedObjectsClient = call[0][2]; }); it('should be callable', () => { diff --git a/src/legacy/server/saved_objects/service/lib/repository.test.js b/src/legacy/server/saved_objects/service/lib/repository.test.js index 0e4df19ae7fb6..e51b131805529 100644 --- a/src/legacy/server/saved_objects/service/lib/repository.test.js +++ b/src/legacy/server/saved_objects/service/lib/repository.test.js @@ -17,11 +17,9 @@ * under the License. */ -import sinon from 'sinon'; import { delay } from 'bluebird'; import { SavedObjectsRepository } from './repository'; import * as getSearchDslNS from './search_dsl/search_dsl'; -import { getSearchDsl } from './search_dsl'; import * as errors from './errors'; import elasticsearch from 'elasticsearch'; import { SavedObjectsSchema } from '../../schema'; @@ -33,8 +31,6 @@ import { encodeHitVersion } from '../../version'; // so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient. describe('SavedObjectsRepository', () => { - const sandbox = sinon.createSandbox(); - let callAdminCluster; let onBeforeWrite; let savedObjectsRepository; @@ -245,10 +241,10 @@ describe('SavedObjectsRepository', () => { }); beforeEach(() => { - callAdminCluster = sandbox.stub(); - onBeforeWrite = sandbox.stub(); + callAdminCluster = jest.fn(); + onBeforeWrite = jest.fn(); migrator = { - migrateDocument: sinon.spy((doc) => doc), + migrateDocument: jest.fn((doc) => doc), awaitMigration: async () => ({ status: 'skipped' }), }; @@ -267,17 +263,17 @@ describe('SavedObjectsRepository', () => { onBeforeWrite }); - sandbox.stub(savedObjectsRepository, '_getCurrentTime').returns(mockTimestamp); - sandbox.stub(getSearchDslNS, 'getSearchDsl').returns({}); + savedObjectsRepository._getCurrentTime = jest.fn(() => mockTimestamp); + getSearchDslNS.getSearchDsl = jest.fn(() => {}); // eslint-disable-line import/namespace }); afterEach(() => { - sandbox.restore(); + }); describe('#create', () => { beforeEach(() => { - callAdminCluster.callsFake((method, params) => ({ + callAdminCluster.mockImplementation((method, params) => ({ _type: '_doc', _id: params.id, ...mockVersionProps, @@ -285,7 +281,7 @@ describe('SavedObjectsRepository', () => { }); it('waits until migrations are complete before proceeding', async () => { - migrator.awaitMigration = sinon.spy(async () => sinon.assert.notCalled(callAdminCluster)); + migrator.awaitMigration = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled()); await expect(savedObjectsRepository.create('index-pattern', { title: 'Logstash' @@ -293,7 +289,7 @@ describe('SavedObjectsRepository', () => { id: 'logstash-*', namespace: 'foo-namespace', })).resolves.toBeDefined(); - sinon.assert.calledOnce(migrator.awaitMigration); + expect(migrator.awaitMigration).toHaveBeenCalledTimes(1); }); it('formats Elasticsearch response', async () => { @@ -331,9 +327,9 @@ describe('SavedObjectsRepository', () => { title: 'Logstash' }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWith(callAdminCluster, 'index'); - sinon.assert.calledOnce(onBeforeWrite); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('index', expect.any(Object)); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it('migrates the doc', async () => { @@ -349,8 +345,8 @@ describe('SavedObjectsRepository', () => { title: 'Logstash' }); - sinon.assert.calledOnce(callAdminCluster); - expect(callAdminCluster.args[0][1]).toMatchObject({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster.mock.calls[0][1]).toMatchObject({ body: { 'index-pattern': { id: 'logstash-*', title: 'Logstash!!' }, migrationVersion: { foo: '2.3.4' }, @@ -368,9 +364,9 @@ describe('SavedObjectsRepository', () => { id: 'logstash-*', }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWith(callAdminCluster, 'create'); - sinon.assert.calledOnce(onBeforeWrite); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('create', expect.any(Object)); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it('allows for id to be provided', async () => { @@ -378,12 +374,12 @@ describe('SavedObjectsRepository', () => { title: 'Logstash' }, { id: 'logstash-*' }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ id: 'index-pattern:logstash-*' })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it('self-generates an ID', async () => { @@ -391,12 +387,12 @@ describe('SavedObjectsRepository', () => { title: 'Logstash' }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ - id: sinon.match(/index-pattern:[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}/) + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ + id: expect.objectContaining(/index-pattern:[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}/) })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it('prepends namespace to the id and adds namespace to body when providing namespace for namespaced type', async () => { @@ -409,17 +405,19 @@ describe('SavedObjectsRepository', () => { namespace: 'foo-namespace', }, ); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ - id: `foo-namespace:index-pattern:foo-id`, - body: { - [`index-pattern`]: { title: 'Logstash' }, - namespace: 'foo-namespace', - type: 'index-pattern', - updated_at: '2017-08-14T15:49:14.886Z' - } - })); - sinon.assert.calledOnce(onBeforeWrite); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), + expect.objectContaining({ + id: `foo-namespace:index-pattern:foo-id`, + body: expect.objectContaining({ + [`index-pattern`]: { title: 'Logstash' }, + namespace: 'foo-namespace', + type: 'index-pattern', + updated_at: '2017-08-14T15:49:14.886Z' + }), + }) + ); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => { @@ -431,16 +429,16 @@ describe('SavedObjectsRepository', () => { id: 'foo-id' } ); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ id: `index-pattern:foo-id`, - body: { + body: expect.objectContaining({ [`index-pattern`]: { title: 'Logstash' }, type: 'index-pattern', updated_at: '2017-08-14T15:49:14.886Z' - } + }) })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => { @@ -453,23 +451,23 @@ describe('SavedObjectsRepository', () => { namespace: 'foo-namespace', } ); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ id: `globaltype:foo-id`, - body: { + body: expect.objectContaining({ [`globaltype`]: { title: 'Logstash' }, type: 'globaltype', updated_at: '2017-08-14T15:49:14.886Z' - } + }) })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); }); describe('#bulkCreate', () => { it('waits until migrations are complete before proceeding', async () => { - migrator.awaitMigration = sinon.spy(async () => sinon.assert.notCalled(callAdminCluster)); - callAdminCluster.returns({ + migrator.awaitMigration = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled()); + callAdminCluster.mockReturnValue({ items: [ { create: { type: 'config', id: 'config:one', _primary_term: 1, _seq_no: 1 } }, { create: { type: 'index-pattern', id: 'index-pattern:two', _primary_term: 1, _seq_no: 1 } }, @@ -481,11 +479,11 @@ describe('SavedObjectsRepository', () => { { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } } ])).resolves.toBeDefined(); - sinon.assert.calledOnce(migrator.awaitMigration); + expect(migrator.awaitMigration).toHaveBeenCalledTimes(1); }); it('formats Elasticsearch request', async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ items: [ { create: { type: 'config', id: 'config:one', _primary_term: 1, _seq_no: 1 } }, { create: { type: 'index-pattern', id: 'config:two', _primary_term: 1, _seq_no: 1 } }, @@ -497,8 +495,8 @@ describe('SavedObjectsRepository', () => { { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' }, references: [{ name: 'ref_0', type: 'test', id: '2' }] }, ]); - sinon.assert.calledOnce(callAdminCluster); - const bulkCalls = callAdminCluster.args.filter(([path]) => path === 'bulk'); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + const bulkCalls = callAdminCluster.mock.calls.filter(([path]) => path === 'bulk'); expect(bulkCalls.length).toEqual(1); @@ -514,11 +512,11 @@ describe('SavedObjectsRepository', () => { }, ]); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it('migrates the docs', async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ items: [ { create: { @@ -551,7 +549,7 @@ describe('SavedObjectsRepository', () => { { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } } ]); - sinon.assert.calledWithExactly(callAdminCluster, 'bulk', sinon.match({ + expect(callAdminCluster).toHaveBeenCalledWith('bulk', expect.objectContaining({ body: [ { create: { _type: '_doc', _id: 'config:one' } }, { @@ -599,13 +597,13 @@ describe('SavedObjectsRepository', () => { }); it('should overwrite objects if overwrite is truthy', async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ items: [{ create: { type: 'foo', id: 'bar', _primary_term: 1, _seq_no: 1 } }] }); await savedObjectsRepository.bulkCreate([{ type: 'foo', id: 'bar', attributes: {} }], { overwrite: false }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'bulk', sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('bulk', expect.objectContaining({ body: [ // uses create because overwriting is not allowed { create: { _type: '_doc', _id: 'foo:bar' } }, @@ -613,14 +611,18 @@ describe('SavedObjectsRepository', () => { ] })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); - callAdminCluster.resetHistory(); - onBeforeWrite.resetHistory(); + callAdminCluster.mockReset(); + onBeforeWrite.mockReset(); + + callAdminCluster.mockReturnValue({ + items: [{ create: { type: 'foo', id: 'bar', _primary_term: 1, _seq_no: 1 } }] + }); await savedObjectsRepository.bulkCreate([{ type: 'foo', id: 'bar', attributes: {} }], { overwrite: true }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'bulk', sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('bulk', expect.objectContaining({ body: [ // uses index because overwriting is allowed { index: { _type: '_doc', _id: 'foo:bar' } }, @@ -628,11 +630,11 @@ describe('SavedObjectsRepository', () => { ] })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); - it('returns document errors', async () => { - callAdminCluster.returns(Promise.resolve({ + it('mockReturnValue document errors', async () => { + callAdminCluster.mockResolvedValue({ errors: false, items: [{ create: { @@ -649,7 +651,7 @@ describe('SavedObjectsRepository', () => { ...mockVersionProps, } }] - })); + }); const response = await savedObjectsRepository.bulkCreate([ { type: 'config', id: 'one', attributes: { title: 'Test One' } }, @@ -675,7 +677,7 @@ describe('SavedObjectsRepository', () => { }); it('formats Elasticsearch response', async () => { - callAdminCluster.returns(Promise.resolve({ + callAdminCluster.mockResolvedValue({ errors: false, items: [{ create: { @@ -690,7 +692,7 @@ describe('SavedObjectsRepository', () => { ...mockVersionProps } }] - })); + }); const response = await savedObjectsRepository.bulkCreate([ { type: 'config', id: 'one', attributes: { title: 'Test One' } }, @@ -721,7 +723,7 @@ describe('SavedObjectsRepository', () => { }); it('prepends namespace to the id and adds namespace to body when providing namespace for namespaced type', async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ items: [ { create: { _type: '_doc', _id: 'foo-namespace:config:one', _primary_term: 1, _seq_no: 2 } }, { create: { _type: '_doc', _id: 'foo-namespace:index-pattern:two', _primary_term: 1, _seq_no: 2 } } @@ -736,8 +738,8 @@ describe('SavedObjectsRepository', () => { namespace: 'foo-namespace', }, ); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'bulk', sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('bulk', expect.objectContaining({ body: [ { create: { _type: '_doc', _id: 'foo-namespace:config:one' } }, { @@ -757,34 +759,32 @@ describe('SavedObjectsRepository', () => { }, ] })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => { - callAdminCluster.returns( - Promise.resolve({ - errors: false, - items: [{ - create: { - _type: '_doc', - _id: 'config:one', - ...mockVersionProps - } - }, { - create: { - _type: '_doc', - _id: 'index-pattern:two', - ...mockVersionProps - } - }] - }) - ); + callAdminCluster.mockResolvedValue({ + errors: false, + items: [{ + create: { + _type: '_doc', + _id: 'config:one', + ...mockVersionProps + } + }, { + create: { + _type: '_doc', + _id: 'index-pattern:two', + ...mockVersionProps + } + }] + }); await savedObjectsRepository.bulkCreate([ { type: 'config', id: 'one', attributes: { title: 'Test One' } }, { type: 'index-pattern', id: 'two', attributes: { title: 'Test Two' } } ]); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'bulk', sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('bulk', expect.objectContaining({ body: [ { create: { _type: '_doc', _id: 'config:one' } }, { type: 'config', ...mockTimestampFields, config: { title: 'Test One' }, references: [] }, @@ -792,11 +792,11 @@ describe('SavedObjectsRepository', () => { { type: 'index-pattern', ...mockTimestampFields, 'index-pattern': { title: 'Test Two' }, references: [] } ] })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ items: [{ create: { _type: '_doc', _id: 'globaltype:one', _primary_term: 1, _seq_no: 2 } }] }); await savedObjectsRepository.bulkCreate( @@ -807,14 +807,14 @@ describe('SavedObjectsRepository', () => { namespace: 'foo-namespace', }, ); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'bulk', sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('bulk', expect.objectContaining({ body: [ { create: { _type: '_doc', _id: 'globaltype:one' } }, { type: 'globaltype', ...mockTimestampFields, 'globaltype': { title: 'Test One' }, references: [] }, ] })); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it('should return objects in the same order regardless of type', () => { @@ -824,23 +824,19 @@ describe('SavedObjectsRepository', () => { describe('#delete', () => { it('waits until migrations are complete before proceeding', async () => { - migrator.awaitMigration = sinon.spy(async () => sinon.assert.notCalled(callAdminCluster)); - callAdminCluster.returns({ - result: 'deleted' - }); + migrator.awaitMigration = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled()); + callAdminCluster.mockReturnValue({ result: 'deleted' }); await expect(savedObjectsRepository.delete('index-pattern', 'logstash-*', { namespace: 'foo-namespace', })).resolves.toBeDefined(); - sinon.assert.calledOnce(migrator.awaitMigration); + expect(migrator.awaitMigration).toHaveBeenCalledTimes(1); }); it('throws notFound when ES is unable to find the document', async () => { expect.assertions(1); - callAdminCluster.returns(Promise.resolve({ - result: 'not_found' - })); + callAdminCluster.mockResolvedValue({ result: 'not_found' }); try { await savedObjectsRepository.delete('index-pattern', 'logstash-*'); @@ -850,15 +846,13 @@ describe('SavedObjectsRepository', () => { }); it(`prepends namespace to the id when providing namespace for namespaced type`, async () => { - callAdminCluster.returns({ - result: 'deleted' - }); + callAdminCluster.mockReturnValue({ result: 'deleted' }); await savedObjectsRepository.delete('index-pattern', 'logstash-*', { namespace: 'foo-namespace', }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'delete', { + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('delete', { type: '_doc', id: 'foo-namespace:index-pattern:logstash-*', refresh: 'wait_for', @@ -866,17 +860,15 @@ describe('SavedObjectsRepository', () => { ignore: [404], }); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id when providing no namespace for namespaced type`, async () => { - callAdminCluster.returns({ - result: 'deleted' - }); + callAdminCluster.mockReturnValue({ result: 'deleted' }); await savedObjectsRepository.delete('index-pattern', 'logstash-*'); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'delete', { + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('delete', { type: '_doc', id: 'index-pattern:logstash-*', refresh: 'wait_for', @@ -884,19 +876,17 @@ describe('SavedObjectsRepository', () => { ignore: [404], }); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id when providing namespace for namespace agnostic type`, async () => { - callAdminCluster.returns({ - result: 'deleted' - }); + callAdminCluster.mockReturnValue({ result: 'deleted' }); await savedObjectsRepository.delete('globaltype', 'logstash-*', { namespace: 'foo-namespace', }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'delete', { + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('delete', { type: '_doc', id: 'globaltype:logstash-*', refresh: 'wait_for', @@ -904,39 +894,39 @@ describe('SavedObjectsRepository', () => { ignore: [404], }); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); }); describe('#deleteByNamespace', () => { it('requires namespace to be defined', async () => { - callAdminCluster.returns(deleteByQueryResults); + callAdminCluster.mockReturnValue(deleteByQueryResults); expect(savedObjectsRepository.deleteByNamespace()).rejects.toThrowErrorMatchingSnapshot(); - sinon.assert.notCalled(callAdminCluster); - sinon.assert.notCalled(onBeforeWrite); + expect(callAdminCluster).not.toHaveBeenCalled(); + expect(onBeforeWrite).not.toHaveBeenCalled(); }); it('requires namespace to be a string', async () => { - callAdminCluster.returns(deleteByQueryResults); + callAdminCluster.mockReturnValue(deleteByQueryResults); expect(savedObjectsRepository.deleteByNamespace(['namespace-1', 'namespace-2'])).rejects.toThrowErrorMatchingSnapshot(); - sinon.assert.notCalled(callAdminCluster); - sinon.assert.notCalled(onBeforeWrite); + expect(callAdminCluster).not.toHaveBeenCalled(); + expect(onBeforeWrite).not.toHaveBeenCalled(); }); it('constructs a deleteByQuery call using all types that are namespace aware', async () => { - callAdminCluster.returns(deleteByQueryResults); + callAdminCluster.mockReturnValue(deleteByQueryResults); const result = await savedObjectsRepository.deleteByNamespace('my-namespace'); expect(result).toEqual(deleteByQueryResults); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledOnce(onBeforeWrite); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); - sinon.assert.calledWithExactly(getSearchDsl, mappings, schema, { + expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, schema, { namespace: 'my-namespace', type: ['config', 'index-pattern', 'dashboard'] }); - sinon.assert.calledWithExactly(callAdminCluster, 'deleteByQuery', { + expect(callAdminCluster).toHaveBeenCalledWith('deleteByQuery', { body: { conflicts: 'proceed' }, ignore: [404], index: '.kibana-test', @@ -947,40 +937,40 @@ describe('SavedObjectsRepository', () => { describe('#find', () => { it('waits until migrations are complete before proceeding', async () => { - migrator.awaitMigration = sinon.spy(async () => sinon.assert.notCalled(callAdminCluster)); + migrator.awaitMigration = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled()); - callAdminCluster.returns(noNamespaceSearchResults); + callAdminCluster.mockReturnValue(noNamespaceSearchResults); await expect(savedObjectsRepository.find({ type: 'foo' })).resolves.toBeDefined(); - sinon.assert.calledOnce(migrator.awaitMigration); + expect(migrator.awaitMigration).toHaveBeenCalledTimes(1); }); it('requires type to be defined', async () => { await expect(savedObjectsRepository.find({})).rejects.toThrow(/options\.type must be/); - sinon.assert.notCalled(callAdminCluster); - sinon.assert.notCalled(onBeforeWrite); + expect(callAdminCluster).not.toHaveBeenCalled(); + expect(onBeforeWrite).not.toHaveBeenCalled(); }); it('requires searchFields be an array if defined', async () => { - callAdminCluster.returns(noNamespaceSearchResults); + callAdminCluster.mockReturnValue(noNamespaceSearchResults); try { await savedObjectsRepository.find({ type: 'foo', searchFields: 'string' }); throw new Error('expected find() to reject'); } catch (error) { - sinon.assert.notCalled(callAdminCluster); - sinon.assert.notCalled(onBeforeWrite); + expect(callAdminCluster).not.toHaveBeenCalled(); + expect(onBeforeWrite).not.toHaveBeenCalled(); expect(error.message).toMatch('must be an array'); } }); it('requires fields be an array if defined', async () => { - callAdminCluster.returns(noNamespaceSearchResults); + callAdminCluster.mockReturnValue(noNamespaceSearchResults); try { await savedObjectsRepository.find({ type: 'foo', fields: 'string' }); throw new Error('expected find() to reject'); } catch (error) { - sinon.assert.notCalled(callAdminCluster); - sinon.assert.notCalled(onBeforeWrite); + expect(callAdminCluster).not.toHaveBeenCalled(); + expect(onBeforeWrite).not.toHaveBeenCalled(); expect(error.message).toMatch('must be an array'); } }); @@ -988,7 +978,7 @@ describe('SavedObjectsRepository', () => { it( 'passes mappings, schema, search, defaultSearchOperator, searchFields, type, sortField, sortOrder and hasReference to getSearchDsl', async () => { - callAdminCluster.returns(namespacedSearchResults); + callAdminCluster.mockReturnValue(namespacedSearchResults); const relevantOpts = { namespace: 'foo-namespace', search: 'foo*', @@ -1004,19 +994,19 @@ describe('SavedObjectsRepository', () => { }; await savedObjectsRepository.find(relevantOpts); - sinon.assert.calledOnce(getSearchDsl); - sinon.assert.calledWithExactly(getSearchDsl, mappings, schema, relevantOpts); + expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledTimes(1); + expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, schema, relevantOpts); } ); it('merges output of getSearchDsl into es request body', async () => { - callAdminCluster.returns(noNamespaceSearchResults); - getSearchDsl.returns({ query: 1, aggregations: 2 }); + callAdminCluster.mockReturnValue(noNamespaceSearchResults); + getSearchDslNS.getSearchDsl.mockReturnValue({ query: 1, aggregations: 2 }); await savedObjectsRepository.find({ type: 'foo' }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.notCalled(onBeforeWrite); - sinon.assert.calledWithExactly(callAdminCluster, 'search', sinon.match({ - body: sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(onBeforeWrite).not.toHaveBeenCalled(); + expect(callAdminCluster).toHaveBeenCalledWith('search', expect.objectContaining({ + body: expect.objectContaining({ query: 1, aggregations: 2, }) @@ -1024,7 +1014,7 @@ describe('SavedObjectsRepository', () => { }); it('formats Elasticsearch response when there is no namespace', async () => { - callAdminCluster.returns(noNamespaceSearchResults); + callAdminCluster.mockReturnValue(noNamespaceSearchResults); const count = noNamespaceSearchResults.hits.hits.length; const response = await savedObjectsRepository.find({ type: 'foo' }); @@ -1045,7 +1035,7 @@ describe('SavedObjectsRepository', () => { }); it('formats Elasticsearch response when there is a namespace', async () => { - callAdminCluster.returns(namespacedSearchResults); + callAdminCluster.mockReturnValue(namespacedSearchResults); const count = namespacedSearchResults.hits.hits.length; const response = await savedObjectsRepository.find({ @@ -1069,37 +1059,37 @@ describe('SavedObjectsRepository', () => { }); it('accepts per_page/page', async () => { - callAdminCluster.returns(noNamespaceSearchResults); + callAdminCluster.mockReturnValue(noNamespaceSearchResults); await savedObjectsRepository.find({ type: 'foo', perPage: 10, page: 6 }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ size: 10, from: 50 })); - sinon.assert.notCalled(onBeforeWrite); + expect(onBeforeWrite).not.toHaveBeenCalled(); }); it('can filter by fields', async () => { - callAdminCluster.returns(noNamespaceSearchResults); + callAdminCluster.mockReturnValue(noNamespaceSearchResults); await savedObjectsRepository.find({ type: 'foo', fields: ['title'] }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ _source: [ 'foo.title', 'namespace', 'type', 'title' ] })); - sinon.assert.notCalled(onBeforeWrite); + expect(onBeforeWrite).not.toHaveBeenCalled(); }); it('should set rest_total_hits_as_int to true on a request', async () => { - callAdminCluster.returns(noNamespaceSearchResults); + callAdminCluster.mockReturnValue(noNamespaceSearchResults); await savedObjectsRepository.find({ type: 'foo' }); - sinon.assert.calledOnce(callAdminCluster); - expect(callAdminCluster.args[0][1]).toHaveProperty('rest_total_hits_as_int', true); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster.mock.calls[0][1]).toHaveProperty('rest_total_hits_as_int', true); }); }); @@ -1133,18 +1123,18 @@ describe('SavedObjectsRepository', () => { }; it('waits until migrations are complete before proceeding', async () => { - migrator.awaitMigration = sinon.spy(async () => sinon.assert.notCalled(callAdminCluster)); + migrator.awaitMigration = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled()); - callAdminCluster.returns(Promise.resolve(noNamespaceResult)); + callAdminCluster.mockResolvedValue(noNamespaceResult); await expect(savedObjectsRepository.get('index-pattern', 'logstash-*')).resolves.toBeDefined(); - sinon.assert.calledOnce(migrator.awaitMigration); + expect(migrator.awaitMigration).toHaveBeenCalledTimes(1); }); it('formats Elasticsearch response when there is no namespace', async () => { - callAdminCluster.returns(Promise.resolve(noNamespaceResult)); + callAdminCluster.mockResolvedValue(noNamespaceResult); const response = await savedObjectsRepository.get('index-pattern', 'logstash-*'); - sinon.assert.notCalled(onBeforeWrite); + expect(onBeforeWrite).not.toHaveBeenCalled(); expect(response).toEqual({ id: 'logstash-*', type: 'index-pattern', @@ -1158,9 +1148,9 @@ describe('SavedObjectsRepository', () => { }); it('formats Elasticsearch response when there are namespaces', async () => { - callAdminCluster.returns(Promise.resolve(namespacedResult)); + callAdminCluster.mockResolvedValue(namespacedResult); const response = await savedObjectsRepository.get('index-pattern', 'logstash-*'); - sinon.assert.notCalled(onBeforeWrite); + expect(onBeforeWrite).not.toHaveBeenCalled(); expect(response).toEqual({ id: 'logstash-*', type: 'index-pattern', @@ -1174,40 +1164,40 @@ describe('SavedObjectsRepository', () => { }); it('prepends namespace and type to the id when providing namespace for namespaced type', async () => { - callAdminCluster.returns(Promise.resolve(namespacedResult)); + callAdminCluster.mockResolvedValue(namespacedResult); await savedObjectsRepository.get('index-pattern', 'logstash-*', { namespace: 'foo-namespace', }); - sinon.assert.notCalled(onBeforeWrite); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(onBeforeWrite).not.toHaveBeenCalled(); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ id: 'foo-namespace:index-pattern:logstash-*', type: '_doc' })); }); it(`only prepends type to the id when providing no namespace for namespaced type`, async () => { - callAdminCluster.returns(Promise.resolve(noNamespaceResult)); + callAdminCluster.mockResolvedValue(noNamespaceResult); await savedObjectsRepository.get('index-pattern', 'logstash-*'); - sinon.assert.notCalled(onBeforeWrite); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(onBeforeWrite).not.toHaveBeenCalled(); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ id: 'index-pattern:logstash-*', type: '_doc' })); }); it(`doesn't prepend namespace to the id when providing namespace for namespace agnostic type`, async () => { - callAdminCluster.returns(Promise.resolve(namespacedResult)); + callAdminCluster.mockResolvedValue(namespacedResult); await savedObjectsRepository.get('globaltype', 'logstash-*', { namespace: 'foo-namespace', }); - sinon.assert.notCalled(onBeforeWrite); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(onBeforeWrite).not.toHaveBeenCalled(); + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ id: 'globaltype:logstash-*', type: '_doc' })); @@ -1216,20 +1206,20 @@ describe('SavedObjectsRepository', () => { describe('#bulkGet', () => { it('waits until migrations are complete before proceeding', async () => { - migrator.awaitMigration = sinon.spy(async () => sinon.assert.notCalled(callAdminCluster)); + migrator.awaitMigration = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled()); - callAdminCluster.returns({ docs: [] }); + callAdminCluster.mockReturnValue({ docs: [] }); await expect(savedObjectsRepository.bulkGet([ { id: 'one', type: 'config' }, { id: 'two', type: 'index-pattern' }, { id: 'three', type: 'globaltype' }, ])).resolves.toBeDefined(); - sinon.assert.calledOnce(migrator.awaitMigration); + expect(migrator.awaitMigration).toHaveBeenCalledTimes(1); }); it('prepends type to id when getting objects when there is no namespace', async () => { - callAdminCluster.returns({ docs: [] }); + callAdminCluster.mockReturnValue({ docs: [] }); await savedObjectsRepository.bulkGet([ { id: 'one', type: 'config' }, @@ -1237,8 +1227,8 @@ describe('SavedObjectsRepository', () => { { id: 'three', type: 'globaltype' }, ]); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ body: { docs: [ { _type: '_doc', _id: 'config:one' }, @@ -1248,11 +1238,11 @@ describe('SavedObjectsRepository', () => { } })); - sinon.assert.notCalled(onBeforeWrite); + expect(onBeforeWrite).not.toHaveBeenCalled(); }); it('prepends namespace and type appropriately to id when getting objects when there is a namespace', async () => { - callAdminCluster.returns({ docs: [] }); + callAdminCluster.mockReturnValue({ docs: [] }); await savedObjectsRepository.bulkGet( [ @@ -1264,8 +1254,8 @@ describe('SavedObjectsRepository', () => { } ); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ body: { docs: [ { _type: '_doc', _id: 'foo-namespace:config:one' }, @@ -1275,21 +1265,21 @@ describe('SavedObjectsRepository', () => { } })); - sinon.assert.notCalled(onBeforeWrite); + expect(onBeforeWrite).not.toHaveBeenCalled(); }); - it('returns early for empty objects argument', async () => { - callAdminCluster.returns({ docs: [] }); + it('mockReturnValue early for empty objects argument', async () => { + callAdminCluster.mockReturnValue({ docs: [] }); const response = await savedObjectsRepository.bulkGet([]); expect(response.saved_objects).toHaveLength(0); - sinon.assert.notCalled(callAdminCluster); - sinon.assert.notCalled(onBeforeWrite); + expect(callAdminCluster).not.toHaveBeenCalled(); + expect(onBeforeWrite).not.toHaveBeenCalled(); }); it('handles missing ids gracefully', async () => { - callAdminCluster.returns(Promise.resolve({ + callAdminCluster.mockResolvedValue({ docs: [{ _type: '_doc', _id: 'config:good', @@ -1301,7 +1291,7 @@ describe('SavedObjectsRepository', () => { _id: 'config:bad', found: false }] - })); + }); const { saved_objects: savedObjects } = await savedObjectsRepository.bulkGet( [{ id: 'good', type: 'config' }, { type: 'config' }] @@ -1314,7 +1304,7 @@ describe('SavedObjectsRepository', () => { }); it('reports error on missed objects', async () => { - callAdminCluster.returns(Promise.resolve({ + callAdminCluster.mockResolvedValue({ docs: [{ _type: '_doc', _id: 'config:good', @@ -1326,14 +1316,14 @@ describe('SavedObjectsRepository', () => { _id: 'config:bad', found: false }] - })); + }); const { saved_objects: savedObjects } = await savedObjectsRepository.bulkGet( [{ id: 'good', type: 'config' }, { id: 'bad', type: 'config' }] ); - sinon.assert.notCalled(onBeforeWrite); - sinon.assert.calledOnce(callAdminCluster); + expect(onBeforeWrite).not.toHaveBeenCalled(); + expect(callAdminCluster).toHaveBeenCalledTimes(1); expect(savedObjects).toHaveLength(2); expect(savedObjects[0]).toEqual({ @@ -1358,25 +1348,25 @@ describe('SavedObjectsRepository', () => { const attributes = { title: 'Testing' }; beforeEach(() => { - callAdminCluster.returns(Promise.resolve({ + callAdminCluster.mockResolvedValue({ _id: `${type}:${id}`, _type: '_doc', ...mockVersionProps, result: 'updated' - })); + }); }); it('waits until migrations are complete before proceeding', async () => { - migrator.awaitMigration = sinon.spy(async () => sinon.assert.notCalled(callAdminCluster)); + migrator.awaitMigration = jest.fn(async () => expect(callAdminCluster).not.toHaveBeenCalled()); await expect( savedObjectsRepository.update('index-pattern', 'logstash-*', attributes, { namespace: 'foo-namespace' }) ).resolves.toBeDefined(); - sinon.assert.calledOnce(migrator.awaitMigration); + expect(migrator.awaitMigration).toHaveReturnedTimes(1); }); - it('returns current ES document _seq_no and _primary_term encoded as version', async () => { + it('mockReturnValue current ES document _seq_no and _primary_term encoded as version', async () => { const response = await savedObjectsRepository.update('index-pattern', 'logstash-*', attributes, { namespace: 'foo-namespace', references: [{ @@ -1412,8 +1402,8 @@ describe('SavedObjectsRepository', () => { } ); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, sinon.match.string, sinon.match({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ if_seq_no: 100, if_primary_term: 200, })); @@ -1431,8 +1421,8 @@ describe('SavedObjectsRepository', () => { }], }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'update', { + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('update', { type: '_doc', id: 'foo-namespace:index-pattern:logstash-*', body: { @@ -1451,7 +1441,7 @@ describe('SavedObjectsRepository', () => { index: '.kibana-test' }); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => { @@ -1465,8 +1455,8 @@ describe('SavedObjectsRepository', () => { }], }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'update', { + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('update', { type: '_doc', id: 'index-pattern:logstash-*', body: { @@ -1485,7 +1475,7 @@ describe('SavedObjectsRepository', () => { index: '.kibana-test' }); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => { @@ -1500,8 +1490,8 @@ describe('SavedObjectsRepository', () => { }], }); - sinon.assert.calledOnce(callAdminCluster); - sinon.assert.calledWithExactly(callAdminCluster, 'update', { + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledWith('update', { type: '_doc', id: 'globaltype:foo', body: { @@ -1520,13 +1510,13 @@ describe('SavedObjectsRepository', () => { index: '.kibana-test' }); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); }); describe('#incrementCounter', () => { beforeEach(() => { - callAdminCluster.callsFake((method, params) => ({ + callAdminCluster.mockImplementation((method, params) => ({ _type: '_doc', _id: params.id, ...mockVersionProps, @@ -1546,7 +1536,7 @@ describe('SavedObjectsRepository', () => { }); it('formats Elasticsearch response', async () => { - callAdminCluster.callsFake((method, params) => ({ + callAdminCluster.mockImplementation((method, params) => ({ _type: '_doc', _id: params.id, ...mockVersionProps, @@ -1603,8 +1593,8 @@ describe('SavedObjectsRepository', () => { } ); - sinon.assert.calledOnce(callAdminCluster); - expect(callAdminCluster.firstCall.args[1]).toMatchObject({ + expect(callAdminCluster).toHaveBeenCalledTimes(1); + expect(callAdminCluster.mock.calls[0][1]).toMatchObject({ body: { upsert: { config: { buildNum: 42 }, @@ -1622,33 +1612,33 @@ describe('SavedObjectsRepository', () => { namespace: 'foo-namespace', }); - sinon.assert.calledOnce(callAdminCluster); + expect(callAdminCluster).toHaveBeenCalledTimes(1); - const requestDoc = callAdminCluster.firstCall.args[1]; + const requestDoc = callAdminCluster.mock.calls[0][1]; expect(requestDoc.id).toBe('foo-namespace:config:6.0.0-alpha1'); expect(requestDoc.body.script.params.type).toBe('config'); expect(requestDoc.body.upsert.type).toBe('config'); expect(requestDoc).toHaveProperty('body.upsert.config'); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id or add namespace property when providing no namespace for namespaced type`, async () => { await savedObjectsRepository.incrementCounter('config', '6.0.0-alpha1', 'buildNum'); - sinon.assert.calledOnce(callAdminCluster); + expect(callAdminCluster).toHaveBeenCalledTimes(1); - const requestDoc = callAdminCluster.firstCall.args[1]; + const requestDoc = callAdminCluster.mock.calls[0][1]; expect(requestDoc.id).toBe('config:6.0.0-alpha1'); expect(requestDoc.body.script.params.type).toBe('config'); expect(requestDoc.body.upsert.type).toBe('config'); expect(requestDoc).toHaveProperty('body.upsert.config'); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it(`doesn't prepend namespace to the id or add namespace property when providing namespace for namespace agnostic type`, async () => { - callAdminCluster.callsFake((method, params) => ({ + callAdminCluster.mockImplementation((method, params) => ({ _type: '_doc', _id: params.id, ...mockVersionProps, @@ -1669,15 +1659,15 @@ describe('SavedObjectsRepository', () => { namespace: 'foo-namespace', }); - sinon.assert.calledOnce(callAdminCluster); + expect(callAdminCluster).toHaveBeenCalledTimes(1); - const requestDoc = callAdminCluster.firstCall.args[1]; + const requestDoc = callAdminCluster.mock.calls[0][1]; expect(requestDoc.id).toBe('globaltype:foo'); expect(requestDoc.body.script.params.type).toBe('globaltype'); expect(requestDoc.body.upsert.type).toBe('globaltype'); expect(requestDoc).toHaveProperty('body.upsert.globaltype'); - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); }); it('should assert that the "type" and "counterFieldName" arguments are strings', () => { @@ -1741,29 +1731,29 @@ describe('SavedObjectsRepository', () => { describe('onBeforeWrite', () => { it('blocks calls to callCluster of requests', async () => { - onBeforeWrite.returns(delay(500)); - callAdminCluster.returns({ result: 'deleted', found: true }); + onBeforeWrite.mockReturnValue(delay(500)); + callAdminCluster.mockReturnValue({ result: 'deleted', found: true }); const deletePromise = savedObjectsRepository.delete('foo', 'id'); await delay(100); - sinon.assert.calledOnce(onBeforeWrite); - sinon.assert.notCalled(callAdminCluster); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); + expect(callAdminCluster).not.toHaveBeenCalled(); await deletePromise; - sinon.assert.calledOnce(onBeforeWrite); - sinon.assert.calledOnce(callAdminCluster); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); + expect(callAdminCluster).toHaveBeenCalledTimes(1); }); it('can throw es errors and have them decorated as SavedObjectsClient errors', async () => { - expect.assertions(3); + expect.assertions(4); const es401 = new elasticsearch.errors[401]; expect(errors.isNotAuthorizedError(es401)).toBe(false); - onBeforeWrite.throws(es401); + onBeforeWrite.mockImplementation(() => { throw es401; }); try { await savedObjectsRepository.delete('foo', 'id'); } catch (error) { - sinon.assert.calledOnce(onBeforeWrite); + expect(onBeforeWrite).toHaveBeenCalledTimes(1); expect(error).toBe(es401); expect(errors.isNotAuthorizedError(error)).toBe(true); } @@ -1786,7 +1776,7 @@ describe('SavedObjectsRepository', () => { }); it('should return an error object when attempting to \'bulkGet\' an unsupported type', async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ docs: [ { id: 'one', @@ -1836,7 +1826,7 @@ describe('SavedObjectsRepository', () => { }); it('should not return hidden saved ojects when attempting to \'find\' support and unsupported types', async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ hits: { total: 1, hits: [{ @@ -1864,7 +1854,7 @@ describe('SavedObjectsRepository', () => { }); it('should return empty results when attempting to \'find\' an unsupported type', async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ hits: { total: 0, hits: [], @@ -1881,7 +1871,7 @@ describe('SavedObjectsRepository', () => { it('should return empty results when attempting to \'find\' more than one unsupported types', async () => { const findParams = { type: ['hiddenType', 'hiddenType2'] }; - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ status: 200, hits: { total: 0, @@ -1902,7 +1892,7 @@ describe('SavedObjectsRepository', () => { }); it('should error when attempting to \'bulkCreate\' an unsupported type', async () => { - callAdminCluster.returns({ + callAdminCluster.mockReturnValue({ items: [ { index: { diff --git a/src/legacy/server/saved_objects/service/lib/search_dsl/search_dsl.test.js b/src/legacy/server/saved_objects/service/lib/search_dsl/search_dsl.test.js index 0600c01848346..b9567a3a89ae1 100644 --- a/src/legacy/server/saved_objects/service/lib/search_dsl/search_dsl.test.js +++ b/src/legacy/server/saved_objects/service/lib/search_dsl/search_dsl.test.js @@ -17,14 +17,18 @@ * under the License. */ -import sinon from 'sinon'; +jest.mock('./query_params'); +jest.mock('./sorting_params'); + import { getSearchDsl } from './search_dsl'; import * as queryParamsNS from './query_params'; import * as sortParamsNS from './sorting_params'; describe('getSearchDsl', () => { - const sandbox = sinon.createSandbox(); - afterEach(() => sandbox.restore()); + afterEach(() => { + queryParamsNS.getQueryParams.mockReset(); + sortParamsNS.getSortingParams.mockReset(); + }); describe('validation', () => { it('throws when type is not specified', () => { @@ -47,7 +51,6 @@ describe('getSearchDsl', () => { describe('passes control', () => { it('passes (mappings, schema, namespace, type, search, searchFields, hasReference) to getQueryParams', () => { - const spy = sandbox.spy(queryParamsNS, 'getQueryParams'); const mappings = { type: { properties: {} } }; const schema = { isNamespaceAgnostic: () => {} }; const opts = { @@ -63,9 +66,8 @@ describe('getSearchDsl', () => { }; getSearchDsl(mappings, schema, opts); - sinon.assert.calledOnce(spy); - sinon.assert.calledWithExactly( - spy, + expect(queryParamsNS.getQueryParams).toHaveBeenCalledTimes(1); + expect(queryParamsNS.getQueryParams).toHaveBeenCalledWith( mappings, schema, opts.namespace, @@ -78,7 +80,7 @@ describe('getSearchDsl', () => { }); it('passes (mappings, type, sortField, sortOrder) to getSortingParams', () => { - const spy = sandbox.stub(sortParamsNS, 'getSortingParams').returns({}); + sortParamsNS.getSortingParams.mockReturnValue({}); const mappings = { type: { properties: {} } }; const schema = { isNamespaceAgnostic: () => {} }; const opts = { @@ -88,9 +90,8 @@ describe('getSearchDsl', () => { }; getSearchDsl(mappings, schema, opts); - sinon.assert.calledOnce(spy); - sinon.assert.calledWithExactly( - spy, + expect(sortParamsNS.getSortingParams).toHaveBeenCalledTimes(1); + expect(sortParamsNS.getSortingParams).toHaveBeenCalledWith( mappings, opts.type, opts.sortField, @@ -99,8 +100,8 @@ describe('getSearchDsl', () => { }); it('returns combination of getQueryParams and getSortingParams', () => { - sandbox.stub(queryParamsNS, 'getQueryParams').returns({ a: 'a' }); - sandbox.stub(sortParamsNS, 'getSortingParams').returns({ b: 'b' }); + queryParamsNS.getQueryParams.mockReturnValue({ a: 'a' }); + sortParamsNS.getSortingParams.mockReturnValue({ b: 'b' }); expect(getSearchDsl(null, null, { type: 'foo' })).toEqual({ a: 'a', b: 'b' }); }); }); diff --git a/src/legacy/server/saved_objects/service/saved_objects_client.test.js b/src/legacy/server/saved_objects/service/saved_objects_client.test.js index e69b12d1218cc..1ce738b38f3e7 100644 --- a/src/legacy/server/saved_objects/service/saved_objects_client.test.js +++ b/src/legacy/server/saved_objects/service/saved_objects_client.test.js @@ -22,7 +22,7 @@ import { SavedObjectsClient } from './saved_objects_client'; test(`#create`, async () => { const returnValue = Symbol(); const mockRepository = { - create: jest.fn().mockReturnValue(Promise.resolve(returnValue)), + create: jest.fn().mockResolvedValue(returnValue), }; const client = new SavedObjectsClient(mockRepository); @@ -38,7 +38,7 @@ test(`#create`, async () => { test(`#bulkCreate`, async () => { const returnValue = Symbol(); const mockRepository = { - bulkCreate: jest.fn().mockReturnValue(Promise.resolve(returnValue)), + bulkCreate: jest.fn().mockResolvedValue(returnValue), }; const client = new SavedObjectsClient(mockRepository); @@ -53,7 +53,7 @@ test(`#bulkCreate`, async () => { test(`#delete`, async () => { const returnValue = Symbol(); const mockRepository = { - delete: jest.fn().mockReturnValue(Promise.resolve(returnValue)), + delete: jest.fn().mockResolvedValue(returnValue), }; const client = new SavedObjectsClient(mockRepository); @@ -69,7 +69,7 @@ test(`#delete`, async () => { test(`#find`, async () => { const returnValue = Symbol(); const mockRepository = { - find: jest.fn().mockReturnValue(Promise.resolve(returnValue)), + find: jest.fn().mockResolvedValue(returnValue), }; const client = new SavedObjectsClient(mockRepository); @@ -83,7 +83,7 @@ test(`#find`, async () => { test(`#bulkGet`, async () => { const returnValue = Symbol(); const mockRepository = { - bulkGet: jest.fn().mockReturnValue(Promise.resolve(returnValue)), + bulkGet: jest.fn().mockResolvedValue(returnValue), }; const client = new SavedObjectsClient(mockRepository); @@ -98,7 +98,7 @@ test(`#bulkGet`, async () => { test(`#get`, async () => { const returnValue = Symbol(); const mockRepository = { - get: jest.fn().mockReturnValue(Promise.resolve(returnValue)), + get: jest.fn().mockResolvedValue(returnValue), }; const client = new SavedObjectsClient(mockRepository); @@ -114,7 +114,7 @@ test(`#get`, async () => { test(`#update`, async () => { const returnValue = Symbol(); const mockRepository = { - update: jest.fn().mockReturnValue(Promise.resolve(returnValue)), + update: jest.fn().mockResolvedValue(returnValue), }; const client = new SavedObjectsClient(mockRepository); diff --git a/src/legacy/server/saved_objects/validation/validation.test.ts b/src/legacy/server/saved_objects/validation/validation.test.ts index 1af005acb065f..71e220280ba5f 100644 --- a/src/legacy/server/saved_objects/validation/validation.test.ts +++ b/src/legacy/server/saved_objects/validation/validation.test.ts @@ -17,7 +17,6 @@ * under the License. */ -import sinon from 'sinon'; import { docValidator } from './index'; describe('docValidator', () => { @@ -41,15 +40,15 @@ describe('docValidator', () => { test('validates various props', () => { const validators = { - a: sinon.stub(), - b: sinon.stub(), - c: sinon.stub(), + a: jest.fn(), + b: jest.fn(), + c: jest.fn(), }; docValidator(validators)({ type: 'a', b: 'foo' }); - sinon.assert.notCalled(validators.c); + expect(validators.c).not.toHaveBeenCalled(); - expect(validators.a.args).toEqual([[{ type: 'a', b: 'foo' }]]); - expect(validators.b.args).toEqual([[{ type: 'a', b: 'foo' }]]); + expect(validators.a.mock.calls).toEqual([[{ type: 'a', b: 'foo' }]]); + expect(validators.b.mock.calls).toEqual([[{ type: 'a', b: 'foo' }]]); }); }); diff --git a/src/legacy/ui/public/ajax_stream/ajax_stream.test.ts b/src/legacy/ui/public/ajax_stream/ajax_stream.test.ts new file mode 100644 index 0000000000000..755473d1ee237 --- /dev/null +++ b/src/legacy/ui/public/ajax_stream/ajax_stream.test.ts @@ -0,0 +1,199 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { ajaxStream, XMLHttpRequestLike } from './ajax_stream'; + +// tslint:disable-next-line:no-empty +function noop() {} + +describe('ajaxStream', () => { + it('pulls items from the stream and calls the handler', async () => { + const handler = jest.fn(() => ({})); + const { req, sendText, done } = mockRequest(); + const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n'].map(m => `${m.length}:${m}`); + + const promise = ajaxStream('', {}, req, { + url: '/test/endpoint', + onResponse: handler, + }); + + sendText(messages[0]); + sendText(messages[1]); + done(); + + await promise; + expect(handler).toHaveBeenCalledTimes(2); + expect(handler).toHaveBeenCalledWith({ hello: 'world' }); + expect(handler).toHaveBeenCalledWith({ tis: 'fate' }); + }); + + it('handles partial messages', async () => { + const handler = jest.fn(() => ({})); + const { req, sendText, done } = mockRequest(); + const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n'] + .map(m => `${m.length}:${m}`) + .join(''); + + const promise = ajaxStream('', {}, req, { + url: '/test/endpoint', + onResponse: handler, + }); + + for (const s of messages) { + sendText(s); + } + done(); + + await promise; + expect(handler).toHaveBeenCalledTimes(2); + expect(handler).toHaveBeenCalledWith({ hello: 'world' }); + expect(handler).toHaveBeenCalledWith({ tis: 'fate' }); + }); + + it('sends the request', async () => { + const handler = jest.fn(() => ({})); + const { req, done } = mockRequest(); + + const promise = ajaxStream('mehBasePath', { a: 'b' }, req, { + url: '/test/endpoint', + onResponse: handler, + body: 'whatup', + headers: { foo: 'bar' }, + }); + + done(); + + await promise; + expect(req.open).toHaveBeenCalledWith('POST', 'mehBasePath/test/endpoint'); + expect(req.setRequestHeader).toHaveBeenCalledWith('foo', 'bar'); + expect(req.setRequestHeader).toHaveBeenCalledWith('a', 'b'); + expect(req.send).toHaveBeenCalledWith('whatup'); + }); + + it('rejects if network failure', async () => { + const handler = jest.fn(() => ({})); + const { req, done } = mockRequest(); + + const promise = ajaxStream('', {}, req, { + url: '/test/endpoint', + onResponse: handler, + body: 'whatup', + }); + + done(0); + expect(await promise.then(() => true).catch(() => false)).toBeFalsy(); + }); + + it('rejects if http status error', async () => { + const handler = jest.fn(() => ({})); + const { req, done } = mockRequest(); + + const promise = ajaxStream('', {}, req, { + url: '/test/endpoint', + onResponse: handler, + body: 'whatup', + }); + + done(400); + expect(await promise.then(() => true).catch(() => false)).toBeFalsy(); + }); + + it('rejects if the payload contains invalid JSON', async () => { + const handler = jest.fn(() => ({})); + const { req, sendText, done } = mockRequest(); + const messages = ['{ waut? }\n'].map(m => `${m.length}:${m}`).join(''); + + const promise = ajaxStream('', {}, req, { + url: '/test/endpoint', + onResponse: handler, + }); + + sendText(messages); + done(); + + expect(await promise.then(() => true).catch(() => false)).toBeFalsy(); + }); + + it('rejects if the delim is invalid', async () => { + const handler = jest.fn(() => ({})); + const { req, sendText, done } = mockRequest(); + const messages = '{ "hi": "there" }'; + + const promise = ajaxStream('', {}, req, { + url: '/test/endpoint', + onResponse: handler, + }); + + sendText(messages); + done(); + + expect(await promise.then(() => true).catch(({ message }) => message)).toMatch( + /invalid stream response/i + ); + }); + + it('rejects if the handler throws', async () => { + const handler = jest.fn(() => { + throw new Error('DOH!'); + }); + const { req, sendText, done } = mockRequest(); + const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n'] + .map(m => `${m.length}:${m}`) + .join(''); + + const promise = ajaxStream('', {}, req, { + url: '/test/endpoint', + onResponse: handler, + }); + + sendText(messages); + done(); + + expect(await promise.then(() => true).catch(({ message }) => message)).toMatch(/doh!/i); + }); +}); + +function mockRequest() { + const req: XMLHttpRequestLike = { + onprogress: noop, + onreadystatechange: noop, + open: jest.fn(), + readyState: 0, + responseText: '', + send: jest.fn(), + setRequestHeader: jest.fn(), + abort: jest.fn(), + status: 0, + withCredentials: false, + }; + + return { + req, + sendText(text: string) { + req.responseText += text; + req.onreadystatechange(); + req.onprogress(); + }, + done(status = 200) { + req.status = status; + req.readyState = 4; + req.onreadystatechange(); + }, + }; +} diff --git a/src/legacy/ui/public/ajax_stream/ajax_stream.ts b/src/legacy/ui/public/ajax_stream/ajax_stream.ts new file mode 100644 index 0000000000000..74e10e2a271bc --- /dev/null +++ b/src/legacy/ui/public/ajax_stream/ajax_stream.ts @@ -0,0 +1,167 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 { once } from 'lodash'; + +/** + * This file contains the client-side logic for processing a streaming AJAX response. + * This allows things like request batching to process individual batch item results + * as soon as the server sends them, instead of waiting for the entire response before + * client-side processing can begin. + * + * The server sends responses in this format: {length}:{json}, for example: + * + * 18:{"hello":"world"}\n16:{"hello":"you"}\n + */ + +// T is the response payload (the JSON), and we don't really +// care what it's type / shape is. +export type BatchResponseHandler = (result: T) => void; + +export interface BatchOpts { + url: string; + onResponse: BatchResponseHandler; + method?: string; + body?: string; + headers?: { [k: string]: string }; +} + +// The subset of XMLHttpRequest that we use +export interface XMLHttpRequestLike { + abort: () => void; + onreadystatechange: any; + onprogress: any; + open: (method: string, url: string) => void; + readyState: number; + responseText: string; + send: (body?: string) => void; + setRequestHeader: (header: string, value: string) => void; + status: number; + withCredentials: boolean; +} + +// Create a function which, when successively passed streaming response text, +// calls a handler callback with each response in the batch. +function processBatchResponseStream(handler: BatchResponseHandler) { + let index = 0; + + return (text: string) => { + // While there's text to process... + while (index < text.length) { + // Our messages are delimited by colon: len:json + const delim = ':'; + const delimIndex = text.indexOf(delim, index); + const payloadStart = delimIndex + delim.length; + + // We've got an incomplete batch length + if (delimIndex < 0) { + return; + } + + const rawLen = text.slice(index, delimIndex); + const payloadLen = parseInt(rawLen, 10); + const payloadEnd = payloadStart + payloadLen; + + // We've got an invalid batch message (e.g. one without a numeric length: prefix) + if (isNaN(payloadLen)) { + throw new Error(`Invalid stream response length: ${rawLen}`); + } + + // We've got an incomplete batch message + if (text.length < payloadEnd) { + return; + } + + const payload = JSON.parse(text.slice(payloadStart, payloadEnd)); + handler(payload); + + index = payloadEnd; + } + }; +} + +/** + * Sends an AJAX request to the server, and processes the result as a + * streaming HTTP/1 response. + * + * @param basePath - The Kibana basepath + * @param defaultHeaders - The default HTTP headers to be sent with each request + * @param req - The XMLHttpRequest + * @param opts - The request options + * @returns A promise which resolves when the entire batch response has been processed. + */ +export function ajaxStream( + basePath: string, + defaultHeaders: { [k: string]: string }, + req: XMLHttpRequestLike, + opts: BatchOpts +) { + return new Promise((resolve, reject) => { + const { url, method, headers } = opts; + + // There are several paths by which the promise may resolve or reject. We wrap this + // in "once" as a safeguard against cases where we attempt more than one call. (e.g. + // a batch handler fails, so we reject the promise, but then new data comes in for + // a subsequent batch item) + const complete = once((err: Error | undefined = undefined) => + err ? reject(err) : resolve(req) + ); + + // Begin the request + req.open(method || 'POST', `${basePath}/${url.replace(/^\//, '')}`); + req.withCredentials = true; + + // Set the HTTP headers + Object.entries(Object.assign({}, defaultHeaders, headers)).forEach(([k, v]) => + req.setRequestHeader(k, v) + ); + + const batchHandler = processBatchResponseStream(opts.onResponse); + const processBatch = () => { + try { + batchHandler(req.responseText); + } catch (err) { + req.abort(); + complete(err); + } + }; + + req.onprogress = processBatch; + + req.onreadystatechange = () => { + // Older browsers don't support onprogress, so we need + // to call this here, too. It's safe to call this multiple + // times even for the same progress event. + processBatch(); + + // 4 is the magic number that means the request is done + if (req.readyState === 4) { + // 0 indicates a network failure. 400+ messages are considered server errors + if (req.status === 0 || req.status >= 400) { + complete(new Error(`Batch request failed with status ${req.status}`)); + } else { + complete(); + } + } + }; + + // Send the payload to the server + req.send(opts.body); + }); +} diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/build_annotation_request.js b/src/legacy/ui/public/ajax_stream/index.ts similarity index 66% rename from src/legacy/core_plugins/metrics/server/lib/vis_data/build_annotation_request.js rename to src/legacy/ui/public/ajax_stream/index.ts index 1796f3a0a7927..9c5f1832f9c5d 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/build_annotation_request.js +++ b/src/legacy/ui/public/ajax_stream/index.ts @@ -17,11 +17,17 @@ * under the License. */ -import buildProcessorFunction from './build_processor_function'; -import processors from './request_processors/annotations'; +import chrome from 'ui/chrome'; +import { metadata } from 'ui/metadata'; +import { ajaxStream as ajax, BatchOpts } from './ajax_stream'; -export default function buildAnnotationRequest(req, panel, annotation, esQueryConfig, indexPattern) { - const processor = buildProcessorFunction(processors, req, panel, annotation, esQueryConfig, indexPattern); - const doc = processor({}); - return doc; +const defaultHeaders = { + 'Content-Type': 'application/json', + 'kbn-version': metadata.version, +}; + +export { BatchOpts } from './ajax_stream'; + +export function ajaxStream(opts: BatchOpts) { + return ajax(chrome.getBasePath(), defaultHeaders, new XMLHttpRequest(), opts); } diff --git a/src/legacy/ui/public/chrome/api/angular.js b/src/legacy/ui/public/chrome/api/angular.js index 410964beb5909..ace6b6be082d4 100644 --- a/src/legacy/ui/public/chrome/api/angular.js +++ b/src/legacy/ui/public/chrome/api/angular.js @@ -51,7 +51,12 @@ export function initAngularApi(chrome, internals) { .value('esUrl', (function () { const a = document.createElement('a'); a.href = chrome.addBasePath('/elasticsearch'); - return a.href; + return { + host: a.hostname, + port: a.port, + protocol: a.protocol, + pathname: a.pathname + }; }())) .config($locationProvider => { $locationProvider.html5Mode({ diff --git a/src/legacy/ui/public/chrome/api/injected_vars.test.ts b/src/legacy/ui/public/chrome/api/injected_vars.test.ts index 29a64f75813b1..70b63176acc52 100644 --- a/src/legacy/ui/public/chrome/api/injected_vars.test.ts +++ b/src/legacy/ui/public/chrome/api/injected_vars.test.ts @@ -42,43 +42,22 @@ describe('#getInjected()', () => { chrome.getInjected(); chrome.getInjected('foo'); chrome.getInjected('foo', 'bar'); - - expect(newPlatformInjectedMetadata).toMatchInlineSnapshot(` -Object { - "getInjectedVar": [MockFunction] { - "calls": Array [ - Array [ - "foo", - undefined, - ], - Array [ - "foo", - "bar", - ], - ], - "results": Array [ - Object { - "isThrow": false, - "value": undefined, - }, - Object { - "isThrow": false, - "value": undefined, - }, - ], - }, - "getInjectedVars": [MockFunction] { - "calls": Array [ - Array [], - ], - "results": Array [ - Object { - "isThrow": false, - "value": undefined, - }, - ], - }, -} + expect(newPlatformInjectedMetadata.getInjectedVars.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [], +] +`); + expect(newPlatformInjectedMetadata.getInjectedVar.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "foo", + undefined, + ], + Array [ + "foo", + "bar", + ], +] `); }); diff --git a/src/legacy/ui/public/chrome/chrome.js b/src/legacy/ui/public/chrome/chrome.js index 9f6114fecf4bf..566ac97d2a3ec 100644 --- a/src/legacy/ui/public/chrome/chrome.js +++ b/src/legacy/ui/public/chrome/chrome.js @@ -30,6 +30,7 @@ import '../storage'; import '../directives/kbn_src'; import '../watch_multi'; import './services'; +import '../react_components'; import '../i18n'; import { initAngularApi } from './api/angular'; diff --git a/src/legacy/ui/public/chrome/directives/header_global_nav/components/header_help_menu.tsx b/src/legacy/ui/public/chrome/directives/header_global_nav/components/header_help_menu.tsx index 0c1c25469732e..43fbe1323f0b2 100644 --- a/src/legacy/ui/public/chrome/directives/header_global_nav/components/header_help_menu.tsx +++ b/src/legacy/ui/public/chrome/directives/header_global_nav/components/header_help_menu.tsx @@ -127,12 +127,12 @@ class HeaderHelpMenuUI extends Component { ); return ( + // @ts-ignore repositionOnScroll doesn't exist in EuiPopover
- +
diff --git a/src/legacy/ui/public/filter_bar/filter_editor/index.tsx b/src/legacy/ui/public/filter_bar/filter_editor/index.tsx index de301432b1b67..71c1f96a628c7 100644 --- a/src/legacy/ui/public/filter_bar/filter_editor/index.tsx +++ b/src/legacy/ui/public/filter_bar/filter_editor/index.tsx @@ -213,6 +213,7 @@ class FilterEditorUI extends Component { onChange={this.onIndexPatternChange} singleSelection={{ asPlainText: true }} isClearable={false} + data-test-subj="filterIndexPatternsSelect" /> diff --git a/src/legacy/ui/public/index_patterns/index_patterns.js b/src/legacy/ui/public/index_patterns/index_patterns.js index 6766f63df8d33..afaa4a44b0510 100644 --- a/src/legacy/ui/public/index_patterns/index_patterns.js +++ b/src/legacy/ui/public/index_patterns/index_patterns.js @@ -27,7 +27,7 @@ import { fieldFormats } from '../registry/field_formats'; import { uiModules } from '../modules'; const module = uiModules.get('kibana/index_patterns'); -export function IndexPatternsProvider(Notifier, Private, config) { +export function IndexPatternsProvider(Private, config) { const self = this; const IndexPattern = Private(IndexPatternProvider); diff --git a/src/legacy/ui/public/indices/constants/index.js b/src/legacy/ui/public/indices/constants/index.js index 717472ebeffe5..8f15dcca096b2 100644 --- a/src/legacy/ui/public/indices/constants/index.js +++ b/src/legacy/ui/public/indices/constants/index.js @@ -19,7 +19,7 @@ import { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/index_patterns'; -export const INDEX_ILLEGAL_CHARACTERS_VISIBLE = [ ...INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE ]; +export const INDEX_ILLEGAL_CHARACTERS_VISIBLE = [ ...INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE, '*' ]; // Insert the comma into the middle, so it doesn't look as if it has grammatical meaning when // these characters are rendered in the UI. diff --git a/src/legacy/ui/public/notify/__tests__/notifier.js b/src/legacy/ui/public/notify/__tests__/notifier.js index a9ef04b90b481..6e4b101e59f6d 100644 --- a/src/legacy/ui/public/notify/__tests__/notifier.js +++ b/src/legacy/ui/public/notify/__tests__/notifier.js @@ -132,8 +132,8 @@ describe('Notifier', function () { it('has css class helper functions', function () { expect(notify('error').getIconClass()).to.equal('fa fa-warning'); expect(notify('error').getButtonClass()).to.equal('kuiButton--danger'); - expect(notify('error').getAlertClassStack()).to.equal('kbnToast__stack alert alert-danger'); - expect(notify('error').getAlertClass()).to.equal('kbnToast alert alert-danger'); + expect(notify('error').getAlertClassStack()).to.equal('kbnToast kbnToast-isStack kbnToast--danger'); + expect(notify('error').getAlertClass()).to.equal('kbnToast kbnToast--danger'); expect(notify('error').getButtonGroupClass()).to.equal('kbnToast__controls'); expect(notify('error').getToastMessageClass()).to.equal('kbnToast__message'); }); diff --git a/src/legacy/ui/public/notify/banners/index.js b/src/legacy/ui/public/notify/banners/index.js index b4d2a11f61003..ad2fcd650e5c0 100644 --- a/src/legacy/ui/public/notify/banners/index.js +++ b/src/legacy/ui/public/notify/banners/index.js @@ -18,4 +18,4 @@ */ export { GlobalBannerList } from './global_banner_list'; -export { banners } from './banners'; \ No newline at end of file +export { banners } from './banners'; diff --git a/src/legacy/ui/public/notify/notifier.js b/src/legacy/ui/public/notify/notifier.js index 560966e97b72a..735681c8a48d0 100644 --- a/src/legacy/ui/public/notify/notifier.js +++ b/src/legacy/ui/public/notify/notifier.js @@ -87,19 +87,11 @@ function restartNotifTimer(notif, cb) { const typeToButtonClassMap = { danger: 'kuiButton--danger', // NOTE: `error` type is internally named as `danger` - info: 'kuiButton--primary', -}; -const buttonHierarchyClass = index => { - if (index === 0) { - // first action: primary className - return 'kuiButton--primary'; - } - // subsequent actions: secondary/default className - return 'kuiButton--basic'; + info: 'kuiButton--secondary', }; const typeToAlertClassMap = { - danger: `alert-danger`, - info: `alert-info`, + danger: `kbnToast--danger`, + info: `kbnToast--info`, }; function add(notif, cb) { @@ -114,14 +106,14 @@ function add(notif, cb) { }); } else if (notif.customActions) { // wrap all of the custom functions in a close - notif.customActions = notif.customActions.map((action, index) => { + notif.customActions = notif.customActions.map((action) => { return { key: action.text, dataTestSubj: action.dataTestSubj, callback: closeNotif(notif, action.callback, action.text), getButtonClass() { const buttonTypeClass = typeToButtonClassMap[notif.type]; - return `${buttonHierarchyClass(index)} ${buttonTypeClass}`; + return `${buttonTypeClass}`; }, }; }); @@ -134,11 +126,11 @@ function add(notif, cb) { }; // decorate the notification with helper functions for the template - notif.getButtonClass = () => typeToButtonClassMap[notif.type]; - notif.getAlertClassStack = () => `kbnToast__stack alert ${typeToAlertClassMap[notif.type]}`; + notif.getButtonClass = () => `${typeToButtonClassMap[notif.type]}`; + notif.getAlertClassStack = () => `kbnToast kbnToast-isStack ${typeToAlertClassMap[notif.type]}`; notif.getIconClass = () => `fa fa-${notif.icon}`; notif.getToastMessageClass = () => 'kbnToast__message'; - notif.getAlertClass = () => `kbnToast alert ${typeToAlertClassMap[notif.type]}`; + notif.getAlertClass = () => `kbnToast ${typeToAlertClassMap[notif.type]}`; notif.getButtonGroupClass = () => 'kbnToast__controls'; let dup = null; diff --git a/src/legacy/ui/public/notify/partials/_toaster.scss b/src/legacy/ui/public/notify/partials/_toaster.scss index b3584daf98254..92dab77a3ae9d 100644 --- a/src/legacy/ui/public/notify/partials/_toaster.scss +++ b/src/legacy/ui/public/notify/partials/_toaster.scss @@ -1,3 +1,7 @@ +// REDO Bootstrap alternatives to match EUI +@import '@elastic/eui/src/components/call_out/variables'; +@import '@elastic/eui/src/components/call_out/mixins'; + .kbnToaster__container { visibility: visible; width: 100%; @@ -17,16 +21,10 @@ border: none; } - .alert { - padding: $euiSizeXS $euiSize; - margin: 0; - border-radius: 0; - border: none; - } - .kbnToast { display: flex; align-items: center; + padding: $euiSizeXS $euiSize; > * { flex: 0 0 auto; @@ -38,13 +36,14 @@ } .kbnToast__message { + @include euiFontSizeS; text-overflow: ellipsis; flex: 1 1 auto; - line-height: normal; white-space: normal; } - .kbnToast__stack { + .kbnToast-isStack { + @include euiFontSizeS; padding-bottom: $euiSizeS; pre { @@ -61,3 +60,37 @@ display: flex; } } + +$kbnToastTypes: ( + info: 'primary', + warning: 'warning', + danger: 'danger', + success: 'success', +); + +@each $name, $color in $kbnToastTypes { + $foreground: euiCallOutColor($color, 'foreground'); + + .kbnToast--#{$name} { + background-color: euiCallOutColor($color, 'background'); + color: $foreground; + + // Fix dark mode contrast by forcing button colors to use the same foreground color + // Override hover/focus text color changes by using !important + @if ($name = 'danger') { + .kuiButton--danger, + .kuiButton--danger:hover { + color: $foreground !important; + border-color: $foreground; + } + } + + @if ($name = 'info') { + .kuiButton--secondary, + .kuiButton--secondary:hover { + color: $foreground !important; + border-color: $foreground; + } + } + } +} diff --git a/src/legacy/ui/public/notify/partials/toaster.html b/src/legacy/ui/public/notify/partials/toaster.html index 5d5b0ab72af83..24ceb8ec22a26 100644 --- a/src/legacy/ui/public/notify/partials/toaster.html +++ b/src/legacy/ui/public/notify/partials/toaster.html @@ -29,7 +29,7 @@
); } - -export default Distribution; diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.js b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.ts similarity index 68% rename from x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.js rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.ts index 78e9d9977645a..e00428da8328b 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.js +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.ts @@ -5,10 +5,11 @@ */ import { connect } from 'react-redux'; -import { ErrorGroupDetails } from './view'; +import { IReduxState } from '../../../store/rootReducer'; import { getUrlParams } from '../../../store/urlParams'; +import { ErrorGroupDetailsView } from './view'; -function mapStateToProps(state = {}) { +function mapStateToProps(state = {} as IReduxState) { return { urlParams: getUrlParams(state), location: state.location @@ -17,7 +18,7 @@ function mapStateToProps(state = {}) { const mapDispatchToProps = {}; -export default connect( +export const ErrorGroupDetails = connect( mapStateToProps, mapDispatchToProps -)(ErrorGroupDetails); +)(ErrorGroupDetailsView); diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/view.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/view.tsx index ec02fb774bbfe..82f6216062ec6 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/view.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/view.tsx @@ -25,8 +25,7 @@ import { // @ts-ignore import { KueryBar } from '../../shared/KueryBar'; import { DetailView } from './DetailView'; -// @ts-ignore -import Distribution from './Distribution'; +import { ErrorDistribution } from './Distribution'; const Titles = styled.div` margin-bottom: ${px(units.plus)}; @@ -67,7 +66,7 @@ interface Props { location: Location; } -export function ErrorGroupDetails({ urlParams, location }: Props) { +export function ErrorGroupDetailsView({ urlParams, location }: Props) { return ( } + render={({ data }) => ( + + )} /> {showDetails && ( List', () => { const storeState = {}; const wrapper = mount( - + , storeState ); diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.js b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx similarity index 78% rename from x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.js rename to x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx index a1a1c2c841baf..80778b10447ef 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.js +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx @@ -4,25 +4,35 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { EuiBasicTable, EuiBadge, EuiToolTip } from '@elastic/eui'; +import { EuiBadge, EuiBasicTable, EuiToolTip } from '@elastic/eui'; import numeral from '@elastic/numeral'; +import { i18n } from '@kbn/i18n'; +import { Location } from 'history'; import moment from 'moment'; -import { toQuery, fromQuery, history } from '../../../shared/Links/url_helpers'; -import { KibanaLink } from '../../../shared/Links/KibanaLink'; +import React, { Component } from 'react'; import styled from 'styled-components'; +import { IUrlParams } from 'x-pack/plugins/apm/public/store/urlParams'; +import { ErrorGroupListAPIResponse } from 'x-pack/plugins/apm/server/lib/errors/get_error_groups'; +import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; import { - unit, - px, fontFamilyCode, fontSizes, - truncate + px, + truncate, + unit } from '../../../../style/variables'; -import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; -import { i18n } from '@kbn/i18n'; +import { KibanaLink } from '../../../shared/Links/KibanaLink'; +import { fromQuery, history, toQuery } from '../../../shared/Links/url_helpers'; -function paginateItems({ items, pageIndex, pageSize }) { +function paginateItems({ + items, + pageIndex, + pageSize +}: { + items: any[]; + pageIndex: number; + pageSize: number; +}) { return items.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize); } @@ -44,15 +54,33 @@ const Culprit = styled.div` font-family: ${fontFamilyCode}; `; -export class ErrorGroupList extends Component { - state = { +interface Props { + location: Location; + urlParams: IUrlParams; + items: ErrorGroupListAPIResponse; +} + +interface ITableChange { + page: { index?: number; size?: number }; + sort: { + field?: string; + direction?: string; + }; +} + +interface State { + page: { index?: number; size?: number }; +} + +export class ErrorGroupList extends Component { + public state = { page: { index: 0, size: 25 } }; - onTableChange = ({ page = {}, sort = {} }) => { + public onTableChange = ({ page = {}, sort = {} }: ITableChange) => { this.setState({ page }); const { location } = this.props; @@ -67,7 +95,7 @@ export class ErrorGroupList extends Component { }); }; - render() { + public render() { const { items } = this.props; const { serviceName, sortDirection, sortField } = this.props.urlParams; @@ -85,7 +113,7 @@ export class ErrorGroupList extends Component { field: 'groupId', sortable: false, width: px(unit * 6), - render: groupId => { + render: (groupId: string) => { return ( {groupId.slice(0, 5) || NOT_AVAILABLE_LABEL} @@ -103,7 +131,7 @@ export class ErrorGroupList extends Component { field: 'message', sortable: false, width: '50%', - render: (message, item) => { + render: (message: string, item: ErrorGroupListAPIResponse[0]) => { return ( + render: (isUnhandled: boolean) => isUnhandled === false && ( {i18n.translate('xpack.apm.errorsTable.unhandledLabel', { @@ -146,7 +174,7 @@ export class ErrorGroupList extends Component { field: 'occurrenceCount', sortable: true, dataType: 'number', - render: value => + render: (value?: number) => value ? numeral(value).format('0.[0]a') : NOT_AVAILABLE_LABEL }, { @@ -159,7 +187,8 @@ export class ErrorGroupList extends Component { } ), align: 'right', - render: value => (value ? moment(value).fromNow() : NOT_AVAILABLE_LABEL) + render: (value?: number) => + value ? moment(value).fromNow() : NOT_AVAILABLE_LABEL } ]; @@ -186,7 +215,3 @@ export class ErrorGroupList extends Component { ); } } - -ErrorGroupList.propTypes = { - location: PropTypes.object.isRequired -}; diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx index 7ad174951076e..5d75b208765e8 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx @@ -4,16 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Location } from 'history'; import React from 'react'; -// @ts-ignore -import Distribution from 'x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution'; +import { ErrorDistribution } from 'x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution'; import { ErrorDistributionRequest } from 'x-pack/plugins/apm/public/store/reactReduxRequest/errorDistribution'; import { IUrlParams } from 'x-pack/plugins/apm/public/store/urlParams'; import { ErrorGroupOverviewRequest } from '../../../store/reactReduxRequest/errorGroupList'; -// @ts-ignore import { ErrorGroupList } from './List'; interface ErrorGroupOverviewProps { @@ -32,20 +30,14 @@ const ErrorGroupOverview: React.SFC = ({ ( - - - {i18n.translate( - 'xpack.apm.serviceDetails.metrics.errorOccurrencesChartTitle', - { - defaultMessage: 'Error occurrences' - } - )} - - - } + title={i18n.translate( + 'xpack.apm.serviceDetails.metrics.errorOccurrencesChartTitle', + { + defaultMessage: 'Error occurrences' + } + )} /> )} /> diff --git a/x-pack/plugins/apm/public/components/app/Main/GlobalProgress/index.js b/x-pack/plugins/apm/public/components/app/Main/GlobalProgress/index.ts similarity index 60% rename from x-pack/plugins/apm/public/components/app/Main/GlobalProgress/index.js rename to x-pack/plugins/apm/public/components/app/Main/GlobalProgress/index.ts index c8173d88343e9..f9a8b4ecb2dd3 100644 --- a/x-pack/plugins/apm/public/components/app/Main/GlobalProgress/index.js +++ b/x-pack/plugins/apm/public/components/app/Main/GlobalProgress/index.ts @@ -4,22 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ +import { get, some } from 'lodash'; import { connect } from 'react-redux'; -import view from './view'; -import { some, get } from 'lodash'; +import { IReduxState } from 'x-pack/plugins/apm/public/store/rootReducer'; import { STATUS } from '../../../../constants/index'; +import { GlobalProgressView } from './view'; -function getIsLoading(state) { +function getIsLoading(state: IReduxState) { return some( state.reactReduxRequest, subState => get(subState, 'status') === STATUS.LOADING ); } -function mapStateToProps(state = {}) { +function mapStateToProps(state = {} as IReduxState) { return { isLoading: getIsLoading(state) }; } -export default connect(mapStateToProps)(view); +export const GlobalProgress = connect(mapStateToProps)(GlobalProgressView); diff --git a/x-pack/plugins/apm/public/components/app/Main/GlobalProgress/view.js b/x-pack/plugins/apm/public/components/app/Main/GlobalProgress/view.tsx similarity index 74% rename from x-pack/plugins/apm/public/components/app/Main/GlobalProgress/view.js rename to x-pack/plugins/apm/public/components/app/Main/GlobalProgress/view.tsx index 64644faecf5d0..77995714eff42 100644 --- a/x-pack/plugins/apm/public/components/app/Main/GlobalProgress/view.js +++ b/x-pack/plugins/apm/public/components/app/Main/GlobalProgress/view.tsx @@ -4,10 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ +import { EuiDelayHide, EuiPortal, EuiProgress } from '@elastic/eui'; import React from 'react'; -import { EuiPortal, EuiProgress, EuiDelayHide } from '@elastic/eui'; -export default ({ isLoading }) => { +interface Props { + isLoading: boolean; +} + +export function GlobalProgressView({ isLoading }: Props) { return ( { )} /> ); -}; +} diff --git a/x-pack/plugins/apm/public/components/app/Main/LicenseCheck/InvalidLicenseNotification.tsx b/x-pack/plugins/apm/public/components/app/Main/LicenseCheck/InvalidLicenseNotification.tsx new file mode 100644 index 0000000000000..40d8f59cd9249 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/Main/LicenseCheck/InvalidLicenseNotification.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import chrome from 'ui/chrome'; + +const MANAGE_LICENSE_URL = `${chrome.getBasePath()}/app/kibana#/management/elasticsearch/license_management`; + +export function InvalidLicenseNotification() { + return ( + + {i18n.translate('xpack.apm.invalidLicense.title', { + defaultMessage: 'Invalid License' + })} + + } + body={ +

+ {i18n.translate('xpack.apm.invalidLicense.message', { + defaultMessage: + 'The APM UI is not available because your current license has expired or is no longer valid.' + })} +

+ } + actions={[ + + {i18n.translate('xpack.apm.invalidLicense.licenseManagementLink', { + defaultMessage: 'Manage your license' + })} + + ]} + /> + ); +} diff --git a/x-pack/plugins/apm/public/components/app/Main/LicenseChecker/index.js b/x-pack/plugins/apm/public/components/app/Main/LicenseCheck/index.tsx similarity index 52% rename from x-pack/plugins/apm/public/components/app/Main/LicenseChecker/index.js rename to x-pack/plugins/apm/public/components/app/Main/LicenseCheck/index.tsx index e675f99e05e01..8db0127fb4a2b 100644 --- a/x-pack/plugins/apm/public/components/app/Main/LicenseChecker/index.js +++ b/x-pack/plugins/apm/public/components/app/Main/LicenseCheck/index.tsx @@ -6,18 +6,19 @@ import React from 'react'; import { STATUS } from '../../../../constants/index'; import { LicenceRequest } from '../../../../store/reactReduxRequest/license'; +import { InvalidLicenseNotification } from './InvalidLicenseNotification'; -function LicenseChecker() { +export const LicenseCheck: React.FunctionComponent = ({ children }) => { return ( { - if (status === STATUS.SUCCESS && !data.license.is_active) { - window.location = '#/invalid-license'; + render={({ data: licenseData, status: licenseStatus }) => { + const hasValidLicense = licenseData.license.is_active; + if (licenseStatus === STATUS.SUCCESS && !hasValidLicense) { + return ; } - return null; + + return children; }} /> ); -} - -export default LicenseChecker; +}; diff --git a/x-pack/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.js b/x-pack/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.tsx similarity index 66% rename from x-pack/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.js rename to x-pack/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.tsx index 78e5ee127ceda..190899ef0e098 100644 --- a/x-pack/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.js +++ b/x-pack/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.tsx @@ -4,18 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Location } from 'history'; import { Component } from 'react'; -class ScrollToTopOnPathChange extends Component { - componentDidUpdate(prevProps) { +interface Props { + location: Location; +} + +export class ScrollToTopOnPathChange extends Component { + public componentDidUpdate(prevProps: Props) { if (this.props.location.pathname !== prevProps.location.pathname) { window.scrollTo(0, 0); } } - render() { + public render() { return null; } } - -export default ScrollToTopOnPathChange; diff --git a/x-pack/plugins/apm/public/components/app/Main/index.js b/x-pack/plugins/apm/public/components/app/Main/index.tsx similarity index 69% rename from x-pack/plugins/apm/public/components/app/Main/index.js rename to x-pack/plugins/apm/public/components/app/Main/index.tsx index cbf1925e5650a..407d1394f81f8 100644 --- a/x-pack/plugins/apm/public/components/app/Main/index.js +++ b/x-pack/plugins/apm/public/components/app/Main/index.tsx @@ -5,12 +5,14 @@ */ import React from 'react'; -import styled from 'styled-components'; import { Route, Switch } from 'react-router-dom'; -import { routes } from './routeConfig'; -import ScrollToTopOnPathChange from './ScrollToTopOnPathChange'; -import { px, units, unit, topNavHeight } from '../../../style/variables'; +import styled from 'styled-components'; +import { px, topNavHeight, unit, units } from '../../../style/variables'; +// @ts-ignore import ConnectRouterToRedux from '../../shared/ConnectRouterToRedux'; +import { LicenseCheck } from './LicenseCheck'; +import { routes } from './routeConfig'; +import { ScrollToTopOnPathChange } from './ScrollToTopOnPathChange'; import { UpdateBreadcrumbs } from './UpdateBreadcrumbs'; const MainContainer = styled.div` @@ -19,17 +21,19 @@ const MainContainer = styled.div` min-height: calc(100vh - ${topNavHeight}); `; -export default function Main() { +export function Main() { return ( - - {routes.map((route, i) => ( - - ))} - + + + {routes.map((route, i) => ( + + ))} + + ); } diff --git a/x-pack/plugins/apm/public/components/app/Main/routeConfig.tsx b/x-pack/plugins/apm/public/components/app/Main/routeConfig.tsx index d089dc5d8caad..8a14c939b6c42 100644 --- a/x-pack/plugins/apm/public/components/app/Main/routeConfig.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/routeConfig.tsx @@ -8,8 +8,7 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; import { legacyDecodeURIComponent } from 'x-pack/plugins/apm/public/components/shared/Links/url_helpers'; -// @ts-ignore -import ErrorGroupDetails from '../ErrorGroupDetails'; +import { ErrorGroupDetails } from '../ErrorGroupDetails'; import { ServiceDetails } from '../ServiceDetails'; import { TransactionDetails } from '../TransactionDetails'; import { Home } from './Home'; @@ -37,20 +36,6 @@ export const routes: BreadcrumbRoute[] = [ render: renderAsRedirectTo('/services'), breadcrumb: 'APM' }, - { - exact: true, - path: '/invalid-license', - breadcrumb: i18n.translate('xpack.apm.breadcrumb.invalidLicenseTitle', { - defaultMessage: 'Invalid License' - }), - render: () => ( -
- {i18n.translate('xpack.apm.invalidLicenseLabel', { - defaultMessage: 'Invalid license' - })} -
- ) - }, { exact: true, path: '/services', diff --git a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts index 6a3268a6187b6..8c854e8ea6e2b 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts @@ -22,7 +22,7 @@ describe('createErrorGroupWatch', () => { let tmpl: any; beforeEach(async () => { chrome.getInjected = jest.fn().mockReturnValue('myIndexPattern'); - jest.spyOn(uuid, 'v4').mockReturnValue('mocked-uuid'); + jest.spyOn(uuid, 'v4').mockReturnValue(new Buffer('mocked-uuid')); jest.spyOn(rest, 'createWatch').mockReturnValue(undefined); createWatchResponse = await createErrorGroupWatch({ diff --git a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceMetrics.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceMetrics.tsx index 0cbcd914e08bd..cc9b4f2395165 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceMetrics.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceMetrics.tsx @@ -8,14 +8,12 @@ import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, - EuiSpacer, - EuiTitle + EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Location } from 'history'; import React from 'react'; -// @ts-ignore -import Distribution from 'x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution'; +import { ErrorDistribution } from 'x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution'; import { SyncChartGroup } from 'x-pack/plugins/apm/public/components/shared/charts/SyncChartGroup'; import { TransactionCharts } from 'x-pack/plugins/apm/public/components/shared/charts/TransactionCharts'; import { ErrorDistributionRequest } from 'x-pack/plugins/apm/public/store/reactReduxRequest/errorDistribution'; @@ -51,20 +49,14 @@ export function ServiceMetrics({ urlParams, location }: ServiceMetricsProps) { ( - - - {i18n.translate( - 'xpack.apm.serviceDetails.metrics.errorOccurrencesChartTitle', - { - defaultMessage: 'Error occurrences' - } - )} - - - } + title={i18n.translate( + 'xpack.apm.serviceDetails.metrics.errorOccurrencesChartTitle', + { + defaultMessage: 'Error occurrences' + } + )} /> )} /> diff --git a/x-pack/plugins/apm/public/components/app/TraceOverview/view.tsx b/x-pack/plugins/apm/public/components/app/TraceOverview/view.tsx index 4cf247720b76a..34c82f02dca97 100644 --- a/x-pack/plugins/apm/public/components/app/TraceOverview/view.tsx +++ b/x-pack/plugins/apm/public/components/app/TraceOverview/view.tsx @@ -8,7 +8,6 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { RRRRenderResponse } from 'react-redux-request'; import { TraceListAPIResponse } from 'x-pack/plugins/apm/server/lib/traces/get_top_traces'; -// @ts-ignore import { TraceListRequest } from '../../../store/reactReduxRequest/traceList'; import { EmptyMessage } from '../../shared/EmptyMessage'; import { TraceList } from './TraceList'; diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx index 84c9227df24b2..6591ff0e87b3d 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx @@ -56,7 +56,7 @@ interface Props { urlParams: IUrlParams; } -export class Distribution extends Component { +export class TransactionDistribution extends Component { public formatYShort = (t: number) => { return i18n.translate( 'xpack.apm.transactionDetails.transactionsDurationDistributionChart.unitShortLabel', diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/ResponsiveFlyout.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/ResponsiveFlyout.tsx new file mode 100644 index 0000000000000..91fd7360429fe --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/ResponsiveFlyout.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiFlyout } from '@elastic/eui'; + +import styled from 'styled-components'; + +export const ResponsiveFlyout = styled(EuiFlyout)` + width: 100%; + + @media (min-width: 800px) { + width: 90%; + } + + @media (min-width: 1000px) { + width: 80%; + } + + @media (min-width: 1400px) { + width: 70%; + } + + @media (min-width: 2000px) { + width: 60%; + } +`; diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx index 02f8e6b681f3e..162d154a545f8 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx @@ -27,6 +27,7 @@ import { unit, units } from '../../../../../../../style/variables'; +import { TruncateHeightSection } from './TruncateHeightSection'; registerLanguage('sql', sql); @@ -39,6 +40,8 @@ const DatabaseStatement = styled.div` font-size: ${fontSize}; `; +const dbSyntaxLineHeight = unit * 1.5; + interface Props { dbContext?: NonNullable['db']; } @@ -66,20 +69,22 @@ export function DatabaseContext({ dbContext }: Props) { - - {dbContext.statement} - + + + {dbContext.statement} + + diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/TruncateHeightSection.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/TruncateHeightSection.tsx new file mode 100644 index 0000000000000..aba8d991f5d10 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/TruncateHeightSection.tsx @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { Fragment, useEffect, useRef, useState } from 'react'; +import styled from 'styled-components'; +import { px, units } from '../../../../../../../style/variables'; +import { Ellipsis } from '../../../../../../shared/Icons'; + +const ToggleButtonContainer = styled.div` + margin-top: ${px(units.half)}; + user-select: none; +`; + +interface Props { + previewHeight: number; +} + +export const TruncateHeightSection: React.SFC = ({ + children, + previewHeight +}) => { + const contentContainerEl = useRef(null); + + const [showToggle, setShowToggle] = useState(true); + const [isOpen, setIsOpen] = useState(false); + + useEffect( + () => { + if (contentContainerEl.current) { + const shouldShow = + contentContainerEl.current.scrollHeight > previewHeight; + setShowToggle(shouldShow); + } + }, + [children, previewHeight] + ); + + return ( + +
+ {children} +
+ {showToggle ? ( + + { + setIsOpen(!isOpen); + }} + > + {' '} + {isOpen + ? i18n.translate('xpack.apm.toggleHeight.showMoreButtonLabel', { + defaultMessage: 'Show more lines' + }) + : i18n.translate('xpack.apm.toggleHeight.showLessButtonLabel', { + defaultMessage: 'Show fewer lines' + })} + + + ) : null} +
+ ); +}; diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/index.tsx index 280c96d14bb07..4751592a206ba 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/SpanFlyout/index.tsx @@ -9,7 +9,6 @@ import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, - EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiHorizontalRule, @@ -28,6 +27,7 @@ import { Stacktrace } from 'x-pack/plugins/apm/public/components/shared/Stacktra import { Transaction } from 'x-pack/plugins/apm/typings/es_schemas/Transaction'; import { Span } from '../../../../../../../../typings/es_schemas/Span'; import { FlyoutTopLevelProperties } from '../FlyoutTopLevelProperties'; +import { ResponsiveFlyout } from '../ResponsiveFlyout'; import { DatabaseContext } from './DatabaseContext'; import { HttpContext } from './HttpContext'; import { StickySpanProperties } from './StickySpanProperties'; @@ -65,7 +65,7 @@ export function SpanFlyout({ return ( - + @@ -152,7 +152,7 @@ export function SpanFlyout({ ]} /> - + ); } diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx index e47f2bb1cc69c..5f30aa0b5bf61 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx @@ -8,7 +8,6 @@ import { EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiHorizontalRule, @@ -19,7 +18,6 @@ import { import { i18n } from '@kbn/i18n'; import { Location } from 'history'; import React from 'react'; -import styled from 'styled-components'; import { idx } from 'x-pack/plugins/apm/common/idx'; import { TransactionActionMenu } from 'x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu'; import { IUrlParams } from 'x-pack/plugins/apm/public/store/urlParams'; @@ -28,6 +26,7 @@ import { Transaction } from 'x-pack/plugins/apm/typings/es_schemas/Transaction'; import { StickyTransactionProperties } from '../../../StickyTransactionProperties'; import { TransactionPropertiesTableForFlyout } from '../../../TransactionPropertiesTableForFlyout'; import { FlyoutTopLevelProperties } from '../FlyoutTopLevelProperties'; +import { ResponsiveFlyout } from '../ResponsiveFlyout'; interface Props { onClose: () => void; @@ -38,26 +37,6 @@ interface Props { traceRootDuration?: number; } -const ResponsiveFlyout = styled(EuiFlyout)` - width: 100%; - - @media (min-width: 800px) { - width: 90%; - } - - @media (min-width: 1000px) { - width: 70%; - } - - @media (min-width: 1400px) { - width: 50%; - } - - @media (min-width: 2000px) { - width: 35%; - } -`; - function DroppedSpansWarning({ transactionDoc }: { diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/view.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/view.tsx index a626242e72d2d..49ffa75047f4a 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/view.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/view.tsx @@ -16,7 +16,7 @@ import { TransactionCharts } from '../../shared/charts/TransactionCharts'; import { EmptyMessage } from '../../shared/EmptyMessage'; // @ts-ignore import { KueryBar } from '../../shared/KueryBar'; -import { Distribution } from './Distribution'; +import { TransactionDistribution } from './Distribution'; import { Transaction } from './Transaction'; interface Props { @@ -54,7 +54,7 @@ export function TransactionDetailsView({ urlParams, location }: Props) { ( - ; -} - -export function Ellipsis({ horizontal, style, ...props }) { - return ( - - ); -} - -export function Check({ ...props }) { - return ; -} - -export function Close({ ...props }) { - return ; -} diff --git a/x-pack/plugins/apm/public/components/shared/Icons.tsx b/x-pack/plugins/apm/public/components/shared/Icons.tsx new file mode 100644 index 0000000000000..28fd5ab980685 --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/Icons.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiIcon } from '@elastic/eui'; +import React from 'react'; +import { units } from '../../style/variables'; + +export function Ellipsis({ horizontal }: { horizontal: boolean }) { + return ( + + ); +} diff --git a/x-pack/plugins/apm/public/components/shared/Links/KibanaLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/KibanaLink.tsx index e503ac355af9e..6a1bb80e36566 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/KibanaLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/KibanaLink.tsx @@ -23,13 +23,13 @@ interface Props extends KibanaHrefArgs { * * You must remember to pass in location in that case. */ -export function UnconnectedKibanaLink({ +export const UnconnectedKibanaLink: React.FunctionComponent = ({ location, pathname, hash, query, ...props -}: Props) { +}) => { const href = getKibanaHref({ location, pathname, @@ -37,7 +37,9 @@ export function UnconnectedKibanaLink({ query }); return ; -} +}; + +UnconnectedKibanaLink.displayName = 'UnconnectedKibanaLink'; const withLocation = connect( ({ location }: { location: Location }) => ({ location }), diff --git a/x-pack/plugins/apm/public/components/shared/PropertiesTable/__test__/PropertiesTable.test.tsx b/x-pack/plugins/apm/public/components/shared/PropertiesTable/__test__/PropertiesTable.test.tsx index 2d350bc8eea6c..f05ac607f5db3 100644 --- a/x-pack/plugins/apm/public/components/shared/PropertiesTable/__test__/PropertiesTable.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/PropertiesTable/__test__/PropertiesTable.test.tsx @@ -132,7 +132,7 @@ describe('PropertiesTable', () => { it('should render null empty string when no docs are returned', () => { jest .spyOn(agentDocs, 'getAgentFeatureDocsUrl') - .mockImplementation(() => null); + .mockImplementation(() => undefined); expect( shallow( diff --git a/x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStackFrames.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStackFrames.tsx index a0b46c87951ad..1c9e41ef5e1f9 100644 --- a/x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStackFrames.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStackFrames.tsx @@ -9,8 +9,6 @@ import { i18n } from '@kbn/i18n'; import React, { Fragment } from 'react'; import styled from 'styled-components'; import { IStackframe } from 'x-pack/plugins/apm/typings/es_schemas/fields/Stackframe'; -import { units } from '../../../style/variables'; -// @ts-ignore import { Ellipsis } from '../../shared/Icons'; import { Stackframe } from './Stackframe'; @@ -48,10 +46,7 @@ export class LibraryStackFrames extends React.Component {
- {' '} + {' '} {i18n.translate( 'xpack.apm.stacktraceTab.libraryFramesToogleButtonLabel', { diff --git a/x-pack/plugins/apm/public/components/shared/Stacktrace/Variables.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/Variables.tsx index dffdb517297f3..ca764a873e312 100644 --- a/x-pack/plugins/apm/public/components/shared/Stacktrace/Variables.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/Variables.tsx @@ -16,7 +16,6 @@ import { unit, units } from '../../../style/variables'; -// @ts-ignore import { Ellipsis } from '../Icons'; import { PropertiesTable } from '../PropertiesTable'; @@ -59,10 +58,7 @@ export class Variables extends React.Component { return ( - {' '} + {' '} {i18n.translate( 'xpack.apm.stacktraceTab.localVariablesToogleButtonLabel', { defaultMessage: 'Local variables' } diff --git a/x-pack/plugins/apm/public/components/shared/Stacktrace/index.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/index.tsx index bb7b9caea0dd4..775de965c1a7e 100644 --- a/x-pack/plugins/apm/public/components/shared/Stacktrace/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/index.tsx @@ -10,8 +10,6 @@ import { isEmpty, last } from 'lodash'; import React, { Fragment } from 'react'; import { IStackframe } from '../../../../typings/es_schemas/fields/Stackframe'; import { EmptyMessage } from '../../shared/EmptyMessage'; -// @ts-ignore -import { Ellipsis } from '../../shared/Icons'; import { LibraryStackFrames } from './LibraryStackFrames'; import { Stackframe } from './Stackframe'; diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/transactionActionMenuProps.ts b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/transactionActionMenuProps.ts index 8b73129c65f4b..1a0e576ede23a 100644 --- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/transactionActionMenuProps.ts +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/transactionActionMenuProps.ts @@ -50,45 +50,6 @@ const transaction: Transaction = { ], ppid: 0 }, - context: { - request: { - headers: { - Accept: '*/*', - 'User-Agent': 'Python/3.7 aiohttp/3.3.2', - 'Accept-Encoding': 'gzip, deflate' - }, - method: 'GET', - http_version: '1.1', - socket: { - remote_address: '172.18.0.12' - }, - url: { - protocol: 'http', - hostname: '172.18.0.7', - port: '3000', - full: 'http://172.18.0.7:3000/api/products/3/customers', - pathname: '/api/products/3/customers' - } - }, - - system: { - hostname: '8acb9c1a71f3', - ip: '172.18.0.7', - platform: 'linux', - architecture: 'amd64' - }, - response: { - headers: { - 'X-Frame-Options': 'SAMEORIGIN', - Server: 'gunicorn/19.9.0', - Vary: 'Cookie', - 'Content-Length': '31646', - Date: 'Tue, 18 Dec 2018 00:14:45 GMT', - 'Content-Type': 'application/json; charset=utf-8' - }, - status_code: 200 - } - }, transaction: { result: 'HTTP 2xx', duration: { diff --git a/x-pack/plugins/apm/public/index.js b/x-pack/plugins/apm/public/index.tsx similarity index 84% rename from x-pack/plugins/apm/public/index.js rename to x-pack/plugins/apm/public/index.tsx index 5241a8d7e5742..6ebde6c645ee1 100644 --- a/x-pack/plugins/apm/public/index.js +++ b/x-pack/plugins/apm/public/index.tsx @@ -4,30 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import { uiModules } from 'ui/modules'; // eslint-disable-line no-unused-vars -import chrome from 'ui/chrome'; import React, { Fragment } from 'react'; +import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { Router } from 'react-router-dom'; -import ReactDOM from 'react-dom'; -import 'ui/autoload/styles'; +import 'react-vis/dist/style.css'; import 'ui/autoload/all'; +import 'ui/autoload/styles'; +import chrome from 'ui/chrome'; +import { I18nContext } from 'ui/i18n'; +// @ts-ignore +import { uiModules } from 'ui/modules'; import 'uiExports/autocompleteProviders'; -import 'react-vis/dist/style.css'; +import { GlobalHelpExtension } from './components/app/GlobalHelpExtension'; +import { Main } from './components/app/Main'; +import { GlobalProgress } from './components/app/Main/GlobalProgress'; +import { history } from './components/shared/Links/url_helpers'; +// @ts-ignore +import configureStore from './store/config/configureStore'; import './style/global_overrides.css'; - import template from './templates/index.html'; -import Main from './components/app/Main'; - +// @ts-ignore import { initTimepicker } from './utils/timepicker'; -import configureStore from './store/config/configureStore'; -import GlobalProgress from './components/app/Main/GlobalProgress'; -import LicenseChecker from './components/app/Main/LicenseChecker'; -import { GlobalHelpExtension } from './components/app/GlobalHelpExtension'; - -import { history } from './components/shared/Links/url_helpers'; - -import { I18nContext } from 'ui/i18n'; // render APM feedback link in global help menu chrome.helpExtension.set(domElement => { @@ -37,6 +35,7 @@ chrome.helpExtension.set(domElement => { }; }); +// @ts-ignore chrome.setRootTemplate(template); const store = configureStore(); @@ -46,7 +45,6 @@ initTimepicker(history, store.dispatch).then(() => { -
diff --git a/x-pack/plugins/apm/public/store/location.js b/x-pack/plugins/apm/public/store/location.ts similarity index 67% rename from x-pack/plugins/apm/public/store/location.js rename to x-pack/plugins/apm/public/store/location.ts index 5fee25fe10f86..fecf0754ef140 100644 --- a/x-pack/plugins/apm/public/store/location.js +++ b/x-pack/plugins/apm/public/store/location.ts @@ -4,9 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Location } from 'history'; +import { AnyAction } from 'redux'; + export const LOCATION_UPDATE = 'LOCATION_UPDATE'; -function location(state = { pathname: '', search: '', hash: '' }, action) { +export function locationReducer( + state = { pathname: '', search: '', hash: '' }, + action: AnyAction +) { switch (action.type) { case LOCATION_UPDATE: return action.location; @@ -15,11 +21,9 @@ function location(state = { pathname: '', search: '', hash: '' }, action) { } } -export function updateLocation(nextLocation) { +export function updateLocation(nextLocation: Location) { return { type: LOCATION_UPDATE, location: nextLocation }; } - -export default location; diff --git a/x-pack/plugins/apm/public/store/reactReduxRequest/errorDistribution.tsx b/x-pack/plugins/apm/public/store/reactReduxRequest/errorDistribution.tsx index d3dd67e1c50d2..ef91d06bfad6e 100644 --- a/x-pack/plugins/apm/public/store/reactReduxRequest/errorDistribution.tsx +++ b/x-pack/plugins/apm/public/store/reactReduxRequest/errorDistribution.tsx @@ -10,7 +10,6 @@ import { ErrorDistributionAPIResponse } from 'x-pack/plugins/apm/server/lib/erro import { loadErrorDistribution } from '../../services/rest/apm/error_groups'; import { IReduxState } from '../rootReducer'; import { IUrlParams } from '../urlParams'; -// @ts-ignore import { createInitialDataSelector } from './helpers'; const ID = 'errorDistribution'; diff --git a/x-pack/plugins/apm/public/store/reactReduxRequest/errorGroup.tsx b/x-pack/plugins/apm/public/store/reactReduxRequest/errorGroup.tsx index 59d8cf812f96c..37e1983c0a2a8 100644 --- a/x-pack/plugins/apm/public/store/reactReduxRequest/errorGroup.tsx +++ b/x-pack/plugins/apm/public/store/reactReduxRequest/errorGroup.tsx @@ -10,7 +10,6 @@ import { ErrorGroupAPIResponse } from 'x-pack/plugins/apm/server/lib/errors/get_ import { loadErrorGroupDetails } from '../../services/rest/apm/error_groups'; import { IReduxState } from '../rootReducer'; import { IUrlParams } from '../urlParams'; -// @ts-ignore import { createInitialDataSelector } from './helpers'; const ID = 'errorGroupDetails'; diff --git a/x-pack/plugins/apm/public/store/reactReduxRequest/traceList.js b/x-pack/plugins/apm/public/store/reactReduxRequest/traceList.tsx similarity index 65% rename from x-pack/plugins/apm/public/store/reactReduxRequest/traceList.js rename to x-pack/plugins/apm/public/store/reactReduxRequest/traceList.tsx index 83ac94887e44a..6bb98a9a1866a 100644 --- a/x-pack/plugins/apm/public/store/reactReduxRequest/traceList.js +++ b/x-pack/plugins/apm/public/store/reactReduxRequest/traceList.tsx @@ -5,16 +5,19 @@ */ import React from 'react'; -import { Request } from 'react-redux-request'; +import { Request, RRRRender } from 'react-redux-request'; import { createSelector } from 'reselect'; +import { TraceListAPIResponse } from 'x-pack/plugins/apm/server/lib/traces/get_top_traces'; import { loadTraceList } from '../../services/rest/apm/traces'; +import { IReduxState } from '../rootReducer'; +import { IUrlParams } from '../urlParams'; import { createInitialDataSelector } from './helpers'; const ID = 'traceList'; -const INITIAL_DATA = []; +const INITIAL_DATA: TraceListAPIResponse = []; const withInitialData = createInitialDataSelector(INITIAL_DATA); -const selectRRR = (state = {}) => state.reactReduxRequest; +const selectRRR = (state = {} as IReduxState) => state.reactReduxRequest; export const selectTraceList = createSelector( [selectRRR], @@ -23,7 +26,12 @@ export const selectTraceList = createSelector( } ); -export function TraceListRequest({ urlParams = {}, render }) { +interface Props { + urlParams: IUrlParams; + render: RRRRender; +} + +export function TraceListRequest({ urlParams, render }: Props) { const { start, end, kuery } = urlParams; if (!start || !end) { diff --git a/x-pack/plugins/apm/public/store/reactReduxRequest/waterfall.tsx b/x-pack/plugins/apm/public/store/reactReduxRequest/waterfall.tsx index 1a6ebac8d4db3..abd7e73702a3d 100644 --- a/x-pack/plugins/apm/public/store/reactReduxRequest/waterfall.tsx +++ b/x-pack/plugins/apm/public/store/reactReduxRequest/waterfall.tsx @@ -13,8 +13,6 @@ import { } from '../../components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers'; import { loadTrace } from '../../services/rest/apm/traces'; import { IUrlParams } from '../urlParams'; -// @ts-ignore -import { createInitialDataSelector } from './helpers'; export const ID = 'waterfall'; diff --git a/x-pack/plugins/apm/public/store/rootReducer.ts b/x-pack/plugins/apm/public/store/rootReducer.ts index 29051e9484dc3..2395c3f0a6af2 100644 --- a/x-pack/plugins/apm/public/store/rootReducer.ts +++ b/x-pack/plugins/apm/public/store/rootReducer.ts @@ -8,8 +8,7 @@ import { Location } from 'history'; import { reducer } from 'react-redux-request'; import { combineReducers } from 'redux'; import { StringMap } from '../../typings/common'; -// @ts-ignore -import location from './location'; +import { locationReducer } from './location'; import { IUrlParams, urlParamsReducer } from './urlParams'; export interface IReduxState { @@ -19,7 +18,7 @@ export interface IReduxState { } export const rootReducer = combineReducers({ - location, + location: locationReducer, urlParams: urlParamsReducer, reactReduxRequest: reducer }); diff --git a/x-pack/plugins/apm/public/store/urlParams.ts b/x-pack/plugins/apm/public/store/urlParams.ts index 4571f63afb68e..5b73fbe06c64d 100644 --- a/x-pack/plugins/apm/public/store/urlParams.ts +++ b/x-pack/plugins/apm/public/store/urlParams.ts @@ -4,14 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Location } from 'history'; import { compact, pick } from 'lodash'; -import { AnyAction } from 'redux'; import { createSelector } from 'reselect'; import { legacyDecodeURIComponent, toQuery } from '../components/shared/Links/url_helpers'; -// @ts-ignore import { LOCATION_UPDATE } from './location'; import { getDefaultTransactionType } from './reactReduxRequest/serviceDetails'; import { getDefaultDistributionSample } from './reactReduxRequest/transactionDistribution'; @@ -20,6 +19,16 @@ import { IReduxState } from './rootReducer'; // ACTION TYPES export const TIMEPICKER_UPDATE = 'TIMEPICKER_UPDATE'; +interface LocationAction { + type: typeof LOCATION_UPDATE; + location: Location; +} +interface TimepickerAction { + type: typeof TIMEPICKER_UPDATE; + time: { min: number; max: number }; +} +type Action = LocationAction | TimepickerAction; + // "urlParams" contains path and query parameters from the url, that can be easily consumed from // any (container) component with access to the store @@ -28,7 +37,7 @@ export const TIMEPICKER_UPDATE = 'TIMEPICKER_UPDATE'; // serviceName: opbeans-backend (path param) // transactionType: Brewing%20Bot (path param) // transactionId: 1321 (query param) -export function urlParamsReducer(state = {}, action: AnyAction) { +export function urlParamsReducer(state = {}, action: Action) { switch (action.type) { case LOCATION_UPDATE: { const { diff --git a/x-pack/plugins/apm/public/utils/documentation/apm-get-started.ts b/x-pack/plugins/apm/public/utils/documentation/apm-get-started.ts index d1e80f1a0294a..7b8c185c41e24 100644 --- a/x-pack/plugins/apm/public/utils/documentation/apm-get-started.ts +++ b/x-pack/plugins/apm/public/utils/documentation/apm-get-started.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore import { metadata } from 'ui/metadata'; const STACK_VERSION = metadata.branch; diff --git a/x-pack/plugins/apm/public/utils/documentation/xpack.ts b/x-pack/plugins/apm/public/utils/documentation/xpack.ts index 11741fb3ea803..58960dd2d88c7 100644 --- a/x-pack/plugins/apm/public/utils/documentation/xpack.ts +++ b/x-pack/plugins/apm/public/utils/documentation/xpack.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore import { metadata } from 'ui/metadata'; const STACK_VERSION = metadata.branch; diff --git a/x-pack/plugins/apm/public/utils/testHelpers.js b/x-pack/plugins/apm/public/utils/testHelpers.ts similarity index 72% rename from x-pack/plugins/apm/public/utils/testHelpers.js rename to x-pack/plugins/apm/public/utils/testHelpers.ts index 6cc1de8b648e6..93a2659285917 100644 --- a/x-pack/plugins/apm/public/utils/testHelpers.js +++ b/x-pack/plugins/apm/public/utils/testHelpers.ts @@ -6,15 +6,17 @@ /* global jest */ -import { mount } from 'enzyme'; -import moment from 'moment'; -import { createMockStore } from 'redux-test-utils'; -import createHistory from 'history/createHashHistory'; -import PropTypes from 'prop-types'; +import { mount, ReactWrapper } from 'enzyme'; import enzymeToJson from 'enzyme-to-json'; +import createHistory from 'history/createHashHistory'; import 'jest-styled-components'; +import moment from 'moment'; +import { Moment } from 'moment-timezone'; +import PropTypes from 'prop-types'; +// @ts-ignore +import { createMockStore } from 'redux-test-utils'; -export function toJson(wrapper) { +export function toJson(wrapper: ReactWrapper) { return enzymeToJson(wrapper, { noKey: true, mode: 'deep' @@ -27,7 +29,7 @@ const defaultRoute = { }; export function mountWithRouterAndStore( - Component, + Component: React.ReactElement, storeState = {}, route = defaultRoute ) { @@ -51,7 +53,7 @@ export function mountWithRouterAndStore( return mount(Component, options); } -export function mountWithStore(Component, storeState = {}) { +export function mountWithStore(Component: React.ReactElement, storeState = {}) { const store = createMockStore(storeState); const options = { @@ -68,12 +70,16 @@ export function mountWithStore(Component, storeState = {}) { export function mockMoment() { // avoid timezone issues - jest.spyOn(moment.prototype, 'format').mockImplementation(function() { - return `1st of January (mocking ${this.unix()})`; - }); + jest + .spyOn(moment.prototype, 'format') + .mockImplementation(function(this: Moment) { + return `1st of January (mocking ${this.unix()})`; + }); // convert relative time to absolute time to avoid timing issues - jest.spyOn(moment.prototype, 'fromNow').mockImplementation(function() { - return `1337 minutes ago (mocking ${this.unix()})`; - }); + jest + .spyOn(moment.prototype, 'fromNow') + .mockImplementation(function(this: Moment) { + return `1337 minutes ago (mocking ${this.unix()})`; + }); } diff --git a/x-pack/plugins/apm/server/lib/status_check/server_check.js b/x-pack/plugins/apm/server/lib/status_check/server_check.ts similarity index 79% rename from x-pack/plugins/apm/server/lib/status_check/server_check.js rename to x-pack/plugins/apm/server/lib/status_check/server_check.ts index 44748a142d09a..89872d2b0b661 100644 --- a/x-pack/plugins/apm/server/lib/status_check/server_check.js +++ b/x-pack/plugins/apm/server/lib/status_check/server_check.ts @@ -4,13 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import { SearchParams } from 'elasticsearch'; import { OBSERVER_LISTENING } from '../../../common/elasticsearch_fieldnames'; +import { Setup } from '../helpers/setup_request'; // Note: this logic is duplicated in tutorials/apm/envs/on_prem -export async function getServerStatus({ setup }) { +export async function getServerStatus({ setup }: { setup: Setup }) { const { client, config } = setup; - const params = { + const params: SearchParams = { index: config.get('apm_oss.onboardingIndices'), body: { size: 0, diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.test.ts b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.test.ts index 6dc8680a706c4..cb9876af2817d 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.test.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.test.ts @@ -17,7 +17,7 @@ describe('transactionGroupsFetcher', () => { end: 1528977600000, client: clientSpy, config: { - get: jest.fn((key: string) => { + get: jest.fn((key: string) => { switch (key) { case 'apm_oss.transactionIndices': return 'myIndex'; diff --git a/x-pack/plugins/apm/server/routes/errors.js b/x-pack/plugins/apm/server/routes/errors.ts similarity index 83% rename from x-pack/plugins/apm/server/routes/errors.js rename to x-pack/plugins/apm/server/routes/errors.ts index 836efcc61fad5..0804acbe75679 100644 --- a/x-pack/plugins/apm/server/routes/errors.js +++ b/x-pack/plugins/apm/server/routes/errors.ts @@ -4,26 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; import Boom from 'boom'; - +import { Server } from 'hapi'; +import Joi from 'joi'; +import { Legacy } from 'kibana'; import { getDistribution } from '../lib/errors/distribution/get_distribution'; -import { getErrorGroups } from '../lib/errors/get_error_groups'; import { getErrorGroup } from '../lib/errors/get_error_group'; -import { setupRequest } from '../lib/helpers/setup_request'; +import { getErrorGroups } from '../lib/errors/get_error_groups'; import { withDefaultValidators } from '../lib/helpers/input_validation'; +import { setupRequest } from '../lib/helpers/setup_request'; const ROOT = '/api/apm/services/{serviceName}/errors'; -const defaultErrorHandler = err => { +const defaultErrorHandler = (err: Error) => { + // tslint:disable-next-line console.error(err.stack); throw Boom.boomify(err, { statusCode: 400 }); }; -export function initErrorsApi(server) { +export function initErrorsApi(server: Server) { server.route({ method: 'GET', path: ROOT, - config: { + options: { validate: { query: withDefaultValidators({ sortField: Joi.string(), @@ -34,7 +36,10 @@ export function initErrorsApi(server) { handler: req => { const setup = setupRequest(req); const { serviceName } = req.params; - const { sortField, sortDirection } = req.query; + const { sortField, sortDirection } = req.query as { + sortField: string; + sortDirection: 'desc' | 'asc'; + }; return getErrorGroups({ serviceName, @@ -48,7 +53,7 @@ export function initErrorsApi(server) { server.route({ method: 'GET', path: `${ROOT}/{groupId}`, - config: { + options: { validate: { query: withDefaultValidators() } @@ -62,19 +67,19 @@ export function initErrorsApi(server) { } }); - const distributionHandler = req => { + function distributionHandler(req: Legacy.Request) { const setup = setupRequest(req); const { serviceName, groupId } = req.params; return getDistribution({ serviceName, groupId, setup }).catch( defaultErrorHandler ); - }; + } server.route({ method: 'GET', path: `${ROOT}/{groupId}/distribution`, - config: { + options: { validate: { query: withDefaultValidators() } @@ -85,7 +90,7 @@ export function initErrorsApi(server) { server.route({ method: 'GET', path: `${ROOT}/distribution`, - config: { + options: { validate: { query: withDefaultValidators() } diff --git a/x-pack/plugins/apm/server/routes/status_check.js b/x-pack/plugins/apm/server/routes/status_check.ts similarity index 86% rename from x-pack/plugins/apm/server/routes/status_check.js rename to x-pack/plugins/apm/server/routes/status_check.ts index 5aeb79ad73b9b..b0d8e3bc2ddc1 100644 --- a/x-pack/plugins/apm/server/routes/status_check.js +++ b/x-pack/plugins/apm/server/routes/status_check.ts @@ -4,23 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; import Boom from 'boom'; -import { getServerStatus } from '../lib/status_check/server_check'; -import { getAgentStatus } from '../lib/status_check/agent_check'; +import { Server } from 'hapi'; +import Joi from 'joi'; import { setupRequest } from '../lib/helpers/setup_request'; +import { getAgentStatus } from '../lib/status_check/agent_check'; +import { getServerStatus } from '../lib/status_check/server_check'; const ROOT = '/api/apm/status'; -const defaultErrorHandler = err => { +const defaultErrorHandler = (err: Error) => { + // tslint:disable-next-line console.error(err.stack); throw Boom.boomify(err, { statusCode: 400 }); }; -export function initStatusApi(server) { +export function initStatusApi(server: Server) { server.route({ method: 'GET', path: `${ROOT}/server`, - config: { + options: { validate: { query: Joi.object().keys({ _debug: Joi.bool() @@ -36,7 +38,7 @@ export function initStatusApi(server) { server.route({ method: 'GET', path: `${ROOT}/agent`, - config: { + options: { validate: { query: Joi.object().keys({ _debug: Joi.bool() diff --git a/x-pack/plugins/apm/typings/es_schemas/Error.ts b/x-pack/plugins/apm/typings/es_schemas/Error.ts index 19b09ada8ea17..e1081e0b240ae 100644 --- a/x-pack/plugins/apm/typings/es_schemas/Error.ts +++ b/x-pack/plugins/apm/typings/es_schemas/Error.ts @@ -5,12 +5,9 @@ */ import { APMDoc } from './APMDoc'; -import { Container } from './fields/Container'; import { Context } from './fields/Context'; import { Host } from './fields/Host'; import { Http } from './fields/Http'; -import { Kubernetes } from './fields/Kubernetes'; -import { Process } from './fields/Process'; import { Service } from './fields/Service'; import { IStackframe } from './fields/Stackframe'; import { Url } from './fields/Url'; @@ -24,18 +21,13 @@ interface Processor { interface Exception { message?: string; // either message or type are given type?: string; - code?: string; module?: string; - attributes?: unknown; handled?: boolean; stacktrace?: IStackframe[]; } interface Log { message: string; - param_message?: string; - logger_name?: string; - level?: string; stacktrace?: IStackframe[]; } @@ -45,7 +37,6 @@ export interface APMError extends APMDoc { transaction: { id: string; sampled?: boolean; - type?: string; }; error: { id: string; @@ -57,12 +48,9 @@ export interface APMError extends APMDoc { }; // Shared by errors and transactions - container?: Container; context?: Context; host?: Host; http?: Http; - kubernetes?: Kubernetes; - process?: Process; service: Service; url?: Url; user?: User; diff --git a/x-pack/plugins/apm/typings/es_schemas/Span.ts b/x-pack/plugins/apm/typings/es_schemas/Span.ts index be09b7482f83e..fed3535df28a7 100644 --- a/x-pack/plugins/apm/typings/es_schemas/Span.ts +++ b/x-pack/plugins/apm/typings/es_schemas/Span.ts @@ -14,7 +14,9 @@ interface Processor { export interface Span extends APMDoc { processor: Processor; - service: { name: string }; + service: { + name: string; + }; span: { action: string; duration: { us: number }; @@ -28,19 +30,13 @@ export interface Span extends APMDoc { url?: { original?: string; }; - response?: { - status_code?: number; - }; - method?: string; }; db?: { - instance?: string; statement?: string; type?: string; - user?: { - name?: string; - }; }; }; - transaction: { id: string }; + transaction: { + id: string; + }; } diff --git a/x-pack/plugins/apm/typings/es_schemas/fields/Context.ts b/x-pack/plugins/apm/typings/es_schemas/fields/Context.ts index b6b9ad000c703..eed626865868a 100644 --- a/x-pack/plugins/apm/typings/es_schemas/fields/Context.ts +++ b/x-pack/plugins/apm/typings/es_schemas/fields/Context.ts @@ -6,5 +6,4 @@ export interface Context { page?: { url: string }; // only for RUM agent - [key: string]: unknown; } diff --git a/x-pack/plugins/apm/typings/es_schemas/fields/Host.ts b/x-pack/plugins/apm/typings/es_schemas/fields/Host.ts index c0f89cdc5d1d5..51c09e59d9b68 100644 --- a/x-pack/plugins/apm/typings/es_schemas/fields/Host.ts +++ b/x-pack/plugins/apm/typings/es_schemas/fields/Host.ts @@ -5,8 +5,5 @@ */ export interface Host { - architecture?: string; hostname?: string; - ip?: string; - os?: { platform?: string }; } diff --git a/x-pack/plugins/apm/typings/es_schemas/fields/Stackframe.ts b/x-pack/plugins/apm/typings/es_schemas/fields/Stackframe.ts index e59f2920e6caf..36f2b1abd7611 100644 --- a/x-pack/plugins/apm/typings/es_schemas/fields/Stackframe.ts +++ b/x-pack/plugins/apm/typings/es_schemas/fields/Stackframe.ts @@ -6,42 +6,21 @@ interface IStackframeBase { filename: string; - line: { - number: number; - column?: number; - context?: string; - }; - abs_path?: string; - colno?: number; - context_line?: string; function?: string; library_frame?: boolean; exclude_from_grouping?: boolean; - module?: string; context?: { post?: string[]; pre?: string[]; }; - sourcemap?: { - updated?: boolean; - error?: string; - }; vars?: { [key: string]: unknown; }; - orig?: { - filename?: string; - abs_path?: string; - function?: string; - lineno?: number; - colno?: number; - }; } interface IStackframeWithoutLineContext extends IStackframeBase { line: { number: number; - column?: number; context: undefined; }; } @@ -49,7 +28,6 @@ interface IStackframeWithoutLineContext extends IStackframeBase { export interface IStackframeWithLineContext extends IStackframeBase { line: { number: number; - column?: number; context: string; }; } diff --git a/x-pack/plugins/apm/typings/es_schemas/fields/User.ts b/x-pack/plugins/apm/typings/es_schemas/fields/User.ts index 2786410659a8c..c75f9afe5a50f 100644 --- a/x-pack/plugins/apm/typings/es_schemas/fields/User.ts +++ b/x-pack/plugins/apm/typings/es_schemas/fields/User.ts @@ -6,6 +6,4 @@ export interface User { id: string; - username?: string; - email?: string; } diff --git a/x-pack/plugins/apm/typings/react-redux-request.d.ts b/x-pack/plugins/apm/typings/react-redux-request.d.ts index 4db6349ca3e95..de49e9dc648a5 100644 --- a/x-pack/plugins/apm/typings/react-redux-request.d.ts +++ b/x-pack/plugins/apm/typings/react-redux-request.d.ts @@ -18,7 +18,7 @@ declare module 'react-redux-request' { export type RRRRender = ( res: RRRRenderResponse - ) => JSX.Element | null; + ) => React.ReactNode; export interface RequestProps { id: string; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/axisConfig.js b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/axisConfig.js index f2672552f0c31..64ab380035c25 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/axisConfig.js +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/axisConfig.js @@ -23,7 +23,7 @@ export const axisConfig = () => ({ types: ['string'], help: 'Position of the axis labels - top, bottom, left, and right', options: ['top', 'bottom', 'left', 'right'], - default: '', + default: 'left', }, min: { types: ['number', 'date', 'string', 'null'], diff --git a/x-pack/plugins/canvas/common/lib/constants.js b/x-pack/plugins/canvas/common/lib/constants.js index c46916f507769..8c3c5d5dcff30 100644 --- a/x-pack/plugins/canvas/common/lib/constants.js +++ b/x-pack/plugins/canvas/common/lib/constants.js @@ -18,6 +18,6 @@ export const LOCALSTORAGE_AUTOCOMPLETE_ENABLED = `${LOCALSTORAGE_PREFIX}.isAutoc export const LOCALSTORAGE_LASTPAGE = 'canvas:lastpage'; export const FETCH_TIMEOUT = 30000; // 30 seconds export const CANVAS_USAGE_TYPE = 'canvas'; -export const SECURITY_AUTH_MESSAGE = 'Authentication failed'; export const DEFAULT_WORKPAD_CSS = '.canvasPage {\n\n}'; export const VALID_IMAGE_TYPES = ['gif', 'jpeg', 'png', 'svg+xml']; +export const ASSET_MAX_SIZE = 25000; diff --git a/x-pack/plugins/canvas/init.js b/x-pack/plugins/canvas/init.js index d8a0ade990653..9ce3a097d930b 100644 --- a/x-pack/plugins/canvas/init.js +++ b/x-pack/plugins/canvas/init.js @@ -30,8 +30,6 @@ export default async function(server /*options*/) { return { ...kibanaVars, kbnIndex: config.get('kibana.index'), - esShardTimeout: config.get('elasticsearch.shardTimeout'), - esApiVersion: config.get('elasticsearch.apiVersion'), serverFunctions: serverFunctions.toArray(), basePath, reportingBrowserType, diff --git a/x-pack/plugins/canvas/public/apps/workpad/workpad_app/index.js b/x-pack/plugins/canvas/public/apps/workpad/workpad_app/index.js index 119c071e3866d..cbfa41f8d1675 100644 --- a/x-pack/plugins/canvas/public/apps/workpad/workpad_app/index.js +++ b/x-pack/plugins/canvas/public/apps/workpad/workpad_app/index.js @@ -6,7 +6,6 @@ import { connect } from 'react-redux'; import { compose, branch, renderComponent } from 'recompose'; -import { initializeWorkpad } from '../../../state/actions/workpad'; import { selectElement } from '../../../state/actions/transient'; import { canUserWrite, getAppReady } from '../../../state/selectors/app'; import { getWorkpad, isWriteable } from '../../../state/selectors/workpad'; @@ -24,9 +23,6 @@ const mapStateToProps = state => { }; const mapDispatchToProps = dispatch => ({ - initializeWorkpad() { - dispatch(initializeWorkpad()); - }, deselectElement(ev) { ev && ev.stopPropagation(); dispatch(selectElement(null)); diff --git a/x-pack/plugins/canvas/public/apps/workpad/workpad_app/workpad_app.js b/x-pack/plugins/canvas/public/apps/workpad/workpad_app/workpad_app.js index 49ef7ed97e07f..664c071cd0cd2 100644 --- a/x-pack/plugins/canvas/public/apps/workpad/workpad_app/workpad_app.js +++ b/x-pack/plugins/canvas/public/apps/workpad/workpad_app/workpad_app.js @@ -15,13 +15,8 @@ export class WorkpadApp extends React.PureComponent { static propTypes = { isWriteable: PropTypes.bool.isRequired, deselectElement: PropTypes.func, - initializeWorkpad: PropTypes.func.isRequired, }; - componentDidMount() { - this.props.initializeWorkpad(); - } - render() { const { isWriteable, deselectElement } = this.props; diff --git a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.js b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.js index bbde11f8aedac..fc32e64e667eb 100644 --- a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.js +++ b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.js @@ -33,10 +33,11 @@ import { ConfirmModal } from '../confirm_modal'; import { Clipboard } from '../clipboard'; import { Download } from '../download'; import { Loading } from '../loading'; +import { ASSET_MAX_SIZE } from '../../../common/lib/constants'; export class AssetManager extends React.PureComponent { static propTypes = { - assets: PropTypes.array, + assetValues: PropTypes.array, addImageElement: PropTypes.func, removeAsset: PropTypes.func.isRequired, copyAsset: PropTypes.func.isRequired, @@ -147,15 +148,13 @@ export class AssetManager extends React.PureComponent { render() { const { isModalVisible, loading } = this.state; - const { assets } = this.props; - - const assetMaxLimit = 25000; + const { assetValues } = this.props; const assetsTotal = Math.round( - assets.reduce((total, asset) => total + asset.value.length, 0) / 1024 + assetValues.reduce((total, { value }) => total + value.length, 0) / 1024 ); - const percentageUsed = Math.round((assetsTotal / assetMaxLimit) * 100); + const percentageUsed = Math.round((assetsTotal / ASSET_MAX_SIZE) * 100); const emptyAssets = ( @@ -208,9 +207,9 @@ export class AssetManager extends React.PureComponent {

- {assets.length ? ( + {assetValues.length ? ( - {assets.map(this.renderAsset)} + {assetValues.map(this.renderAsset)} ) : ( emptyAssets @@ -221,7 +220,7 @@ export class AssetManager extends React.PureComponent { ({ - assets: Object.values(getAssets(state)), // pull values out of assets object + assets: getAssets(state), selectedPage: getSelectedPage(state), }); @@ -60,19 +60,22 @@ const mapDispatchToProps = dispatch => ({ }); const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { assets } = stateProps; + const { assets, selectedPage } = stateProps; const { onAssetAdd } = dispatchProps; + const assetValues = Object.values(assets); // pull values out of assets object + return { ...ownProps, - ...stateProps, ...dispatchProps, + selectedPage, + assetValues, addImageElement: dispatchProps.addImageElement(stateProps.selectedPage), onAssetAdd: file => { const [type, subtype] = get(file, 'type', '').split('/'); if (type === 'image' && VALID_IMAGE_TYPES.indexOf(subtype) >= 0) { return encode(file).then(dataurl => { const type = 'dataurl'; - const existingId = findExistingAsset(type, dataurl, assets); + const existingId = findExistingAsset(type, dataurl, assetValues); if (existingId) { return existingId; } diff --git a/x-pack/plugins/canvas/public/components/fullscreen_control/fullscreen_control.js b/x-pack/plugins/canvas/public/components/fullscreen_control/fullscreen_control.js index 5a4f73775f6ca..4e2bc84deef7d 100644 --- a/x-pack/plugins/canvas/public/components/fullscreen_control/fullscreen_control.js +++ b/x-pack/plugins/canvas/public/components/fullscreen_control/fullscreen_control.js @@ -9,6 +9,15 @@ import PropTypes from 'prop-types'; import { Shortcuts } from 'react-shortcuts'; export class FullscreenControl extends React.PureComponent { + keyHandler = action => { + const enterFullscreen = action === 'FULLSCREEN'; + const exitFullscreen = this.props.isFullscreen && action === 'FULLSCREEN_EXIT'; + + if (enterFullscreen || exitFullscreen) { + this.toggleFullscreen(); + } + }; + toggleFullscreen = () => { const { setFullscreen, isFullscreen } = this.props; setFullscreen(!isFullscreen); @@ -17,17 +26,11 @@ export class FullscreenControl extends React.PureComponent { render() { const { children, isFullscreen } = this.props; - const keyHandler = action => { - if (action === 'FULLSCREEN' || (isFullscreen && action === 'FULLSCREEN_EXIT')) { - this.toggleFullscreen(); - } - }; - return ( ({ }); export const Toolbar = compose( + pure, connect(mapStateToProps), getContext({ router: PropTypes.object, diff --git a/x-pack/plugins/canvas/public/components/workpad/index.js b/x-pack/plugins/canvas/public/components/workpad/index.js index 40ae5e1d1a664..c030cb1cabcbc 100644 --- a/x-pack/plugins/canvas/public/components/workpad/index.js +++ b/x-pack/plugins/canvas/public/components/workpad/index.js @@ -6,7 +6,7 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -import { compose, withState, withProps, getContext, withHandlers } from 'recompose'; +import { pure, compose, withState, withProps, getContext, withHandlers } from 'recompose'; import { transitionsRegistry } from '../../lib/transitions_registry'; import { undoHistory, redoHistory } from '../../state/actions/history'; import { fetchAllRenderables } from '../../state/actions/elements'; @@ -19,13 +19,19 @@ import { } from '../../state/selectors/workpad'; import { Workpad as Component } from './workpad'; -const mapStateToProps = state => ({ - pages: getPages(state), - selectedPageNumber: getSelectedPageIndex(state) + 1, - totalElementCount: getAllElements(state).length, - workpad: getWorkpad(state), - isFullscreen: getFullscreen(state), -}); +const mapStateToProps = state => { + const { width, height, id: workpadId, css: workpadCss } = getWorkpad(state); + return { + pages: getPages(state), + selectedPageNumber: getSelectedPageIndex(state) + 1, + totalElementCount: getAllElements(state).length, + width, + height, + workpadCss, + workpadId, + isFullscreen: getFullscreen(state), + }; +}; const mapDispatchToProps = { undoHistory, @@ -34,6 +40,7 @@ const mapDispatchToProps = { }; export const Workpad = compose( + pure, getContext({ router: PropTypes.object, }), @@ -68,17 +75,17 @@ export const Workpad = compose( } props.setPrevSelectedPageNumber(props.selectedPageNumber); const transitionPage = Math.max(props.selectedPageNumber, pageNumber) - 1; - const { transition } = props.workpad.pages[transitionPage]; + const { transition } = props.pages[transitionPage]; if (transition) { props.setTransition(transition); } - props.router.navigateTo('loadWorkpad', { id: props.workpad.id, page: pageNumber }); + props.router.navigateTo('loadWorkpad', { id: props.workpadId, page: pageNumber }); }, }), withHandlers({ onTransitionEnd: ({ setTransition }) => () => setTransition(null), nextPage: props => () => { - const pageNumber = Math.min(props.selectedPageNumber + 1, props.workpad.pages.length); + const pageNumber = Math.min(props.selectedPageNumber + 1, props.pages.length); props.onPageChange(pageNumber); }, previousPage: props => () => { diff --git a/x-pack/plugins/canvas/public/components/workpad/workpad.js b/x-pack/plugins/canvas/public/components/workpad/workpad.js index dcdbed0ecea65..956d8a0dbdb63 100644 --- a/x-pack/plugins/canvas/public/components/workpad/workpad.js +++ b/x-pack/plugins/canvas/public/components/workpad/workpad.js @@ -10,33 +10,41 @@ import { Shortcuts } from 'react-shortcuts'; import Style from 'style-it'; import { WorkpadPage } from '../workpad_page'; import { Fullscreen } from '../fullscreen'; -import { setDocTitle } from '../../lib/doc_title'; -export const Workpad = props => { - const { - selectedPageNumber, - getAnimation, - onTransitionEnd, - pages, - totalElementCount, - workpad, - fetchAllRenderables, - undoHistory, - redoHistory, - setGrid, // TODO: Get rid of grid when we improve the layout engine - grid, - nextPage, - previousPage, - isFullscreen, - } = props; +const WORKPAD_CANVAS_BUFFER = 32; // 32px padding around the workpad - const { height, width } = workpad; - const bufferStyle = { - height: isFullscreen ? height : height + 32, - width: isFullscreen ? width : width + 32, +export class Workpad extends React.PureComponent { + static propTypes = { + selectedPageNumber: PropTypes.number.isRequired, + getAnimation: PropTypes.func.isRequired, + onTransitionEnd: PropTypes.func.isRequired, + grid: PropTypes.bool.isRequired, + setGrid: PropTypes.func.isRequired, + pages: PropTypes.array.isRequired, + totalElementCount: PropTypes.number.isRequired, + isFullscreen: PropTypes.bool.isRequired, + width: PropTypes.number.isRequired, + height: PropTypes.number.isRequired, + workpadCss: PropTypes.string, + undoHistory: PropTypes.func.isRequired, + redoHistory: PropTypes.func.isRequired, + nextPage: PropTypes.func.isRequired, + previousPage: PropTypes.func.isRequired, + fetchAllRenderables: PropTypes.func.isRequired, + css: PropTypes.object, }; - const keyHandler = action => { + keyHandler = action => { + const { + fetchAllRenderables, + undoHistory, + redoHistory, + nextPage, + previousPage, + grid, // TODO: Get rid of grid when we improve the layout engine + setGrid, + } = this.props; + // handle keypress events for editor and presentation events // this exists in both contexts if (action === 'REFRESH') { @@ -63,84 +71,84 @@ export const Workpad = props => { } }; - setDocTitle(workpad.name); + render() { + const { + selectedPageNumber, + getAnimation, + onTransitionEnd, + pages, + totalElementCount, + width, + height, + workpadCss, + grid, + isFullscreen, + } = this.props; - return ( -
-
- {!isFullscreen && ( - - )} + const bufferStyle = { + height: isFullscreen ? height : height + WORKPAD_CANVAS_BUFFER, + width: isFullscreen ? width : width + WORKPAD_CANVAS_BUFFER, + }; - - {({ isFullscreen, windowSize }) => { - const scale = Math.min(windowSize.height / height, windowSize.width / width); - const fsStyle = isFullscreen - ? { - transform: `scale3d(${scale}, ${scale}, 1)`, - WebkitTransform: `scale3d(${scale}, ${scale}, 1)`, - msTransform: `scale3d(${scale}, ${scale}, 1)`, - // height, - // width, - height: windowSize.height < height ? 'auto' : height, - width: windowSize.width < width ? 'auto' : width, - } - : {}; + return ( +
+
+ {!isFullscreen && ( + + )} - // NOTE: the data-shared-* attributes here are used for reporting - return Style.it( - workpad.css, -
- {isFullscreen && ( - - )} - {pages.map((page, i) => ( - - ))} + + {({ isFullscreen, windowSize }) => { + const scale = Math.min(windowSize.height / height, windowSize.width / width); + const fsStyle = isFullscreen + ? { + transform: `scale3d(${scale}, ${scale}, 1)`, + WebkitTransform: `scale3d(${scale}, ${scale}, 1)`, + msTransform: `scale3d(${scale}, ${scale}, 1)`, + // height, + // width, + height: windowSize.height < height ? 'auto' : height, + width: windowSize.width < width ? 'auto' : width, + } + : {}; + + // NOTE: the data-shared-* attributes here are used for reporting + return Style.it( + workpadCss,
-
- ); - }} -
+ className={`canvasWorkpad ${isFullscreen ? 'fullscreen' : ''}`} + style={fsStyle} + data-shared-items-count={totalElementCount} + > + {isFullscreen && ( + + )} + {pages.map((page, i) => ( + + ))} +
+
+ ); + }} + +
-
- ); -}; - -Workpad.propTypes = { - selectedPageNumber: PropTypes.number.isRequired, - getAnimation: PropTypes.func.isRequired, - onTransitionEnd: PropTypes.func.isRequired, - grid: PropTypes.bool.isRequired, - setGrid: PropTypes.func.isRequired, - pages: PropTypes.array.isRequired, - totalElementCount: PropTypes.number.isRequired, - isFullscreen: PropTypes.bool.isRequired, - workpad: PropTypes.object.isRequired, - undoHistory: PropTypes.func.isRequired, - redoHistory: PropTypes.func.isRequired, - nextPage: PropTypes.func.isRequired, - previousPage: PropTypes.func.isRequired, - fetchAllRenderables: PropTypes.func.isRequired, - css: PropTypes.object, -}; + ); + } +} diff --git a/x-pack/plugins/canvas/public/components/workpad_header/index.js b/x-pack/plugins/canvas/public/components/workpad_header/index.js index e724b97b0bb4f..66b1988c83c83 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/index.js +++ b/x-pack/plugins/canvas/public/components/workpad_header/index.js @@ -7,7 +7,7 @@ import { compose, withState } from 'recompose'; import { connect } from 'react-redux'; import { canUserWrite } from '../../state/selectors/app'; -import { getWorkpadName, getSelectedPage, isWriteable } from '../../state/selectors/workpad'; +import { getSelectedPage, isWriteable } from '../../state/selectors/workpad'; import { setWriteable } from '../../state/actions/workpad'; import { addElement } from '../../state/actions/elements'; import { WorkpadHeader as Component } from './workpad_header'; @@ -15,7 +15,6 @@ import { WorkpadHeader as Component } from './workpad_header'; const mapStateToProps = state => ({ isWriteable: isWriteable(state) && canUserWrite(state), canUserWrite: canUserWrite(state), - workpadName: getWorkpadName(state), selectedPage: getSelectedPage(state), }); @@ -33,10 +32,10 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => ({ }); export const WorkpadHeader = compose( - withState('showElementModal', 'setShowElementModal', false), connect( mapStateToProps, mapDispatchToProps, mergeProps - ) + ), + withState('showElementModal', 'setShowElementModal', false) )(Component); diff --git a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.js b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.js index 507f7a1a90d98..846c3f1ff5b1e 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.js +++ b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.js @@ -23,122 +23,134 @@ import { WorkpadExport } from '../workpad_export'; import { FullscreenControl } from '../fullscreen_control'; import { RefreshControl } from '../refresh_control'; -export const WorkpadHeader = ({ - isWriteable, - canUserWrite, - toggleWriteable, - addElement, - setShowElementModal, - showElementModal, -}) => { - const keyHandler = action => { +export class WorkpadHeader extends React.PureComponent { + static propTypes = { + isWriteable: PropTypes.bool, + toggleWriteable: PropTypes.func, + addElement: PropTypes.func.isRequired, + showElementModal: PropTypes.bool, + setShowElementModal: PropTypes.func, + }; + + fullscreenButton = ({ toggleFullscreen }) => ( + + + + ); + + keyHandler = action => { if (action === 'EDITING') { - toggleWriteable(); + this.props.toggleWriteable(); } }; - const elementAdd = ( - - setShowElementModal(false)} - className="canvasModal--fixedSize" - maxWidth="1000px" - initialFocus=".canvasElements__filter" - > - { - addElement(element); - setShowElementModal(false); - }} - /> - - setShowElementModal(false)}> - Dismiss - - - - - ); + elementAdd = () => { + const { addElement, setShowElementModal } = this.props; - let readOnlyToolTip = ''; + return ( + + setShowElementModal(false)} + className="canvasModal--fixedSize" + maxWidth="1000px" + initialFocus=".canvasElements__filter" + > + { + addElement(element); + setShowElementModal(false); + }} + /> + + setShowElementModal(false)}> + Dismiss + + + + + ); + }; - if (!canUserWrite) { - readOnlyToolTip = "You don't have permission to edit this workpad"; - } else { - readOnlyToolTip = isWriteable ? 'Hide editing controls' : 'Show editing controls'; - } + getTooltipText = () => { + if (!this.props.canUserWrite) { + return "You don't have permission to edit this workpad"; + } else { + return this.props.isWriteable ? 'Hide editing controls' : 'Show editing controls'; + } + }; - return ( -
- {showElementModal ? elementAdd : null} - - - - - - - - - {({ toggleFullscreen }) => ( - - - - )} - - - - - - - {canUserWrite && ( - - )} - - { - toggleWriteable(); - }} - size="s" - aria-label={readOnlyToolTip} - isDisabled={!canUserWrite} - /> - - - - - {isWriteable ? ( + render() { + const { + isWriteable, + canUserWrite, + toggleWriteable, + setShowElementModal, + showElementModal, + } = this.props; + + return ( +
+ {showElementModal ? this.elementAdd() : null} + - + + + + + + {this.fullscreenButton} + - + - setShowElementModal(true)} - > - Add element - + {canUserWrite && ( + + )} + + { + toggleWriteable(); + }} + size="s" + aria-label={this.getTooltipText()} + isDisabled={!canUserWrite} + /> + - ) : null} - -
- ); -}; - -WorkpadHeader.propTypes = { - isWriteable: PropTypes.bool, - toggleWriteable: PropTypes.func, - addElement: PropTypes.func.isRequired, - showElementModal: PropTypes.bool, - setShowElementModal: PropTypes.func, -}; + {isWriteable ? ( + + + + + + + setShowElementModal(true)} + > + Add element + + + + + ) : null} +
+
+ ); + } +} diff --git a/x-pack/plugins/canvas/public/lib/aeroelastic_kibana.js b/x-pack/plugins/canvas/public/lib/aeroelastic_kibana.js index 54ffd65db0d04..167ebc7819707 100644 --- a/x-pack/plugins/canvas/public/lib/aeroelastic_kibana.js +++ b/x-pack/plugins/canvas/public/lib/aeroelastic_kibana.js @@ -16,10 +16,6 @@ export const aeroelastic = { }, createStore(initialState, onChangeCallback = () => {}, page) { - if (stores.has(page)) { - throw new Error('Only a single aeroelastic store per page should exist'); - } - stores.set(page, state.createStore(initialState, onChangeCallback)); const updateScene = state.select((nextScene, primaryUpdate) => ({ diff --git a/x-pack/plugins/canvas/public/state/middleware/aeroelastic.js b/x-pack/plugins/canvas/public/state/middleware/aeroelastic.js index fe88a21341301..9eff1ab885e7f 100644 --- a/x-pack/plugins/canvas/public/state/middleware/aeroelastic.js +++ b/x-pack/plugins/canvas/public/state/middleware/aeroelastic.js @@ -37,7 +37,7 @@ const aeroelasticConfiguration = { hoverLift: 100, intraGroupManipulation: false, intraGroupSnapOnly: false, - minimumElementSize: 0, + minimumElementSize: 2, persistentGroupName: 'persistentGroup', resizeAnnotationConnectorOffset: 0, resizeAnnotationOffset: 0, diff --git a/x-pack/plugins/canvas/public/state/middleware/workpad_update.js b/x-pack/plugins/canvas/public/state/middleware/workpad_update.js index 574168b110b55..cfb588048ecb3 100644 --- a/x-pack/plugins/canvas/public/state/middleware/workpad_update.js +++ b/x-pack/plugins/canvas/public/state/middleware/workpad_update.js @@ -7,14 +7,21 @@ import { duplicatePage } from '../actions/pages'; import { fetchRenderable } from '../actions/elements'; import { setWriteable } from '../actions/workpad'; -import { getPages, isWriteable } from '../selectors/workpad'; +import { getPages, getWorkpadName, isWriteable } from '../selectors/workpad'; import { getWindow } from '../../lib/get_window'; +import { setDocTitle } from '../../lib/doc_title'; export const workpadUpdate = ({ dispatch, getState }) => next => action => { const oldIsWriteable = isWriteable(getState()); + const oldName = getWorkpadName(getState()); next(action); + // This middleware updates the page title when the workpad name changes + if (getWorkpadName(getState()) !== oldName) { + setDocTitle(getWorkpadName(getState())); + } + // This middleware fetches all of the renderable elements on new, duplicate page if (action.type === duplicatePage.toString()) { // When a page has been duplicated, it will be added as the last page, so fetch it @@ -22,17 +29,16 @@ export const workpadUpdate = ({ dispatch, getState }) => next => action => { const newPage = pages[pages.length - 1]; // For each element on that page, dispatch the action to update it - return newPage.elements.forEach(element => dispatch(fetchRenderable(element))); + newPage.elements.forEach(element => dispatch(fetchRenderable(element))); } // This middleware clears any page selection when the writeable mode changes if (action.type === setWriteable.toString() && oldIsWriteable !== isWriteable(getState())) { const win = getWindow(); - if (typeof win.getSelection !== 'function') { - return; + // check for browser feature before using it + if (typeof win.getSelection === 'function') { + win.getSelection().collapse(document.querySelector('body'), 0); } - - win.getSelection().collapse(document.querySelector('body'), 0); } }; diff --git a/x-pack/plugins/canvas/server/routes/workpad.test.js b/x-pack/plugins/canvas/server/routes/workpad.test.js index 1d8ef5c24fe12..0c8da43267569 100644 --- a/x-pack/plugins/canvas/server/routes/workpad.test.js +++ b/x-pack/plugins/canvas/server/routes/workpad.test.js @@ -81,21 +81,13 @@ Object { "id": "123", } `); - expect(savedObjectsClient.get).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - "123", - ], + expect(savedObjectsClient.get.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", + "123", ], - "results": Array [ - Object { - "isThrow": false, - "value": Promise {}, - }, - ], -} +] `); }); }); @@ -121,28 +113,20 @@ Object { "ok": true, } `); - expect(savedObjectsClient.create).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - Object { - "@created": "2019-02-12T21:01:22.479Z", - "@timestamp": "2019-02-12T21:01:22.479Z", - "foo": true, - }, - Object { - "id": "workpad-123abc", - }, - ], - ], - "results": Array [ + expect(savedObjectsClient.create.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", Object { - "isThrow": false, - "value": Promise {}, + "@created": "2019-02-12T21:01:22.479Z", + "@timestamp": "2019-02-12T21:01:22.479Z", + "foo": true, + }, + Object { + "id": "workpad-123abc", }, ], -} +] `); }); @@ -167,28 +151,20 @@ Object { "ok": true, } `); - expect(savedObjectsClient.create).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - Object { - "@created": "2019-02-12T21:01:22.479Z", - "@timestamp": "2019-02-12T21:01:22.479Z", - "foo": true, - }, - Object { - "id": "123", - }, - ], - ], - "results": Array [ + expect(savedObjectsClient.create.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", Object { - "isThrow": false, - "value": Promise {}, + "@created": "2019-02-12T21:01:22.479Z", + "@timestamp": "2019-02-12T21:01:22.479Z", + "foo": true, + }, + Object { + "id": "123", }, ], -} +] `); }); }); @@ -220,45 +196,29 @@ Object { "ok": true, } `); - expect(savedObjectsClient.get).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - "123", - ], + expect(savedObjectsClient.get.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", + "123", ], - "results": Array [ +] +`); + expect(savedObjectsClient.create.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", Object { - "isThrow": false, - "value": Promise {}, + "@created": "2019-02-12T21:01:22.479Z", + "@timestamp": "2019-02-12T21:01:22.479Z", + "foo": true, }, - ], -} -`); - expect(savedObjectsClient.create).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - Object { - "@created": "2019-02-12T21:01:22.479Z", - "@timestamp": "2019-02-12T21:01:22.479Z", - "foo": true, - }, - Object { - "id": "123", - "overwrite": true, - }, - ], - ], - "results": Array [ Object { - "isThrow": false, - "value": Promise {}, + "id": "123", + "overwrite": true, }, ], -} +] `); }); }); @@ -281,21 +241,13 @@ Object { "ok": true, } `); - expect(savedObjectsClient.delete).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - "123", - ], - ], - "results": Array [ - Object { - "isThrow": false, - "value": Promise {}, - }, + expect(savedObjectsClient.delete.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", + "123", ], -} +] `); }); }); @@ -331,36 +283,28 @@ Object { ], } `); - expect(savedObjectsClient.find).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - Object { - "fields": Array [ - "id", - "name", - "@created", - "@timestamp", - ], - "page": "2", - "perPage": "10", - "search": "abc* | abc", - "searchFields": Array [ - "name", - ], - "sortField": "@timestamp", - "sortOrder": "desc", - "type": "canvas-workpad", - }, - ], - ], - "results": Array [ + expect(savedObjectsClient.find.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ Object { - "isThrow": false, - "value": Promise {}, + "fields": Array [ + "id", + "name", + "@created", + "@timestamp", + ], + "page": "2", + "perPage": "10", + "search": "abc* | abc", + "searchFields": Array [ + "name", + ], + "sortField": "@timestamp", + "sortOrder": "desc", + "type": "canvas-workpad", }, ], -} +] `); }); @@ -403,59 +347,43 @@ Object { "ok": true, } `); - expect(savedObjectsClient.get).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - "123", - ], + expect(savedObjectsClient.get.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", + "123", ], - "results": Array [ - Object { - "isThrow": false, - "value": Promise {}, - }, - ], -} +] `); - expect(savedObjectsClient.create).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - Object { - "@created": "2019-02-12T21:01:22.479Z", - "@timestamp": "2019-02-12T21:01:22.479Z", - "assets": Object { - "asset-123": Object { - "@created": "2019-02-14T00:00:00.000Z", - "id": "asset-123", - "type": "dataurl", - "value": "mockbase64data", - }, - "asset-456": Object { - "@created": "2019-02-15T00:00:00.000Z", - "id": "asset-456", - "type": "dataurl", - "value": "mockbase64data", - }, + expect(savedObjectsClient.create.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", + Object { + "@created": "2019-02-12T21:01:22.479Z", + "@timestamp": "2019-02-12T21:01:22.479Z", + "assets": Object { + "asset-123": Object { + "@created": "2019-02-14T00:00:00.000Z", + "id": "asset-123", + "type": "dataurl", + "value": "mockbase64data", + }, + "asset-456": Object { + "@created": "2019-02-15T00:00:00.000Z", + "id": "asset-456", + "type": "dataurl", + "value": "mockbase64data", }, - "name": "fake workpad", - }, - Object { - "id": "123", - "overwrite": true, }, - ], - ], - "results": Array [ + "name": "fake workpad", + }, Object { - "isThrow": false, - "value": Promise {}, + "id": "123", + "overwrite": true, }, ], -} +] `); }); }); @@ -497,54 +425,38 @@ Object { "ok": true, } `); - expect(savedObjectsClient.get).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - "123", - ], - ], - "results": Array [ - Object { - "isThrow": false, - "value": Promise {}, - }, + expect(savedObjectsClient.get.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", + "123", ], -} +] `); - expect(savedObjectsClient.create).toMatchInlineSnapshot(` -[MockFunction] { - "calls": Array [ - Array [ - "canvas-workpad", - Object { - "@created": "2019-02-12T21:01:22.479Z", - "@timestamp": "2019-02-12T21:01:22.479Z", - "assets": Object { - "asset-123": Object { - "@created": "2019-02-14T00:00:00.000Z", - "id": "asset-123", - "type": "dataurl", - "value": "mockbase64data", - }, + expect(savedObjectsClient.create.mock.calls).toMatchInlineSnapshot(` +Array [ + Array [ + "canvas-workpad", + Object { + "@created": "2019-02-12T21:01:22.479Z", + "@timestamp": "2019-02-12T21:01:22.479Z", + "assets": Object { + "asset-123": Object { + "@created": "2019-02-14T00:00:00.000Z", + "id": "asset-123", + "type": "dataurl", + "value": "mockbase64data", }, - "css": ".canvasPage { color: LavenderBlush; }", - "name": "renamed workpad", - }, - Object { - "id": "123", - "overwrite": true, }, - ], - ], - "results": Array [ + "css": ".canvasPage { color: LavenderBlush; }", + "name": "renamed workpad", + }, Object { - "isThrow": false, - "value": Promise {}, + "id": "123", + "overwrite": true, }, ], -} +] `); }); }); diff --git a/x-pack/plugins/cross_cluster_replication/index.js b/x-pack/plugins/cross_cluster_replication/index.js index c538ed78a85b6..4b2d513a43f22 100644 --- a/x-pack/plugins/cross_cluster_replication/index.js +++ b/x-pack/plugins/cross_cluster_replication/index.js @@ -22,7 +22,10 @@ export function crossClusterReplication(kibana) { injectDefaultVars(server) { const config = server.config(); return { - ccrUiEnabled: config.get('xpack.ccr.ui.enabled'), + ccrUiEnabled: ( + config.get('xpack.ccr.ui.enabled') + && config.get('xpack.remote_clusters.ui.enabled') + ), }; }, }, @@ -38,7 +41,13 @@ export function crossClusterReplication(kibana) { enabled: Joi.boolean().default(true), }).default(); }, - + isEnabled(config) { + return ( + config.get('xpack.ccr.enabled') && + config.get('xpack.index_management.enabled') && + config.get('xpack.remote_clusters.enabled') + ); + }, init: function initCcrPlugin(server) { registerLicenseChecker(server); registerRoutes(server); diff --git a/x-pack/plugins/cross_cluster_replication/server/lib/call_with_request_factory/call_with_request_factory.js b/x-pack/plugins/cross_cluster_replication/server/lib/call_with_request_factory/call_with_request_factory.js index 4d541d0d711c2..8d1a1fd723ca7 100644 --- a/x-pack/plugins/cross_cluster_replication/server/lib/call_with_request_factory/call_with_request_factory.js +++ b/x-pack/plugins/cross_cluster_replication/server/lib/call_with_request_factory/call_with_request_factory.js @@ -8,10 +8,7 @@ import { once } from 'lodash'; import { elasticsearchJsPlugin } from '../../client/elasticsearch_ccr'; const callWithRequest = once(server => { - const config = { - plugins: [ elasticsearchJsPlugin ], - ...server.config().get('elasticsearch') - }; + const config = { plugins: [ elasticsearchJsPlugin ], }; const cluster = server.plugins.elasticsearch.createCluster('ccr', config); return cluster.callWithRequest; }); diff --git a/x-pack/plugins/cross_cluster_replication/server/lib/license_pre_routing_factory/index.js b/x-pack/plugins/cross_cluster_replication/server/lib/license_pre_routing_factory/index.js index a6903bcf11a78..0743e443955f4 100644 --- a/x-pack/plugins/cross_cluster_replication/server/lib/license_pre_routing_factory/index.js +++ b/x-pack/plugins/cross_cluster_replication/server/lib/license_pre_routing_factory/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { licensePreRoutingFactory } from './license_pre_routing_factory'; \ No newline at end of file +export { licensePreRoutingFactory } from './license_pre_routing_factory'; diff --git a/x-pack/plugins/graph/index.js b/x-pack/plugins/graph/index.js index 39dbc148772ec..626142eaf212f 100644 --- a/x-pack/plugins/graph/index.js +++ b/x-pack/plugins/graph/index.js @@ -45,8 +45,6 @@ export function graph(kibana) { server.injectUiAppVars('graph', () => { const config = server.config(); return { - esApiVersion: config.get('elasticsearch.apiVersion'), - esShardTimeout: config.get('elasticsearch.shardTimeout'), graphSavePolicy: config.get('xpack.graph.savePolicy'), canEditDrillDownUrls: config.get('xpack.graph.canEditDrillDownUrls') }; diff --git a/x-pack/plugins/grokdebugger/common/constants/index.js b/x-pack/plugins/grokdebugger/common/constants/index.js index c37101b73078a..12e440d7ed858 100644 --- a/x-pack/plugins/grokdebugger/common/constants/index.js +++ b/x-pack/plugins/grokdebugger/common/constants/index.js @@ -6,4 +6,4 @@ export { ROUTES } from './routes'; export { PLUGIN } from './plugin'; -export { EDITOR } from './editor'; \ No newline at end of file +export { EDITOR } from './editor'; diff --git a/x-pack/plugins/grokdebugger/server/lib/check_license/index.js b/x-pack/plugins/grokdebugger/server/lib/check_license/index.js index a6c7fae3e1adc..f2c070fd44b6e 100644 --- a/x-pack/plugins/grokdebugger/server/lib/check_license/index.js +++ b/x-pack/plugins/grokdebugger/server/lib/check_license/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { checkLicense } from './check_license'; \ No newline at end of file +export { checkLicense } from './check_license'; diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js index f9b0ea05e7b3c..75e707839afab 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js +++ b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.js @@ -29,6 +29,7 @@ import { policyNameContainsSpaceErrorMessage, policyNameMustBeDifferentErrorMessage, policyNameAlreadyUsedErrorMessage, + maximumDocumentsRequiredMessage, } from '../../public/store/selectors/lifecycle'; let server; @@ -184,7 +185,7 @@ describe('edit policy', () => { maxAgeInput.simulate('change', { target: { value: '' } }); rendered.update(); save(rendered); - expectedErrorMessages(rendered, [maximumSizeRequiredMessage, maximumAgeRequiredMessage]); + expectedErrorMessages(rendered, [maximumSizeRequiredMessage, maximumAgeRequiredMessage, maximumDocumentsRequiredMessage]); }); test('should show number above 0 required error when trying to save with -1 for max size', () => { const rendered = mountWithIntl(component); diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/components/index.js b/x-pack/plugins/index_lifecycle_management/public/sections/components/index.js index e87d7b34b8f68..a2ae37780b9f9 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/components/index.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/components/index.js @@ -7,4 +7,4 @@ export { ActiveBadge } from './active_badge'; export { LearnMoreLink } from './learn_more_link'; export { PhaseErrorMessage } from './phase_error_message'; -export { OptionalLabel } from './optional_label'; \ No newline at end of file +export { OptionalLabel } from './optional_label'; diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/components/learn_more_link.js b/x-pack/plugins/index_lifecycle_management/public/sections/components/learn_more_link.js index 38192f6391072..420ca972c222c 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/components/learn_more_link.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/components/learn_more_link.js @@ -34,4 +34,4 @@ export class LearnMoreLinkUi extends React.PureComponent { } } -export const LearnMoreLink = injectI18n(LearnMoreLinkUi); \ No newline at end of file +export const LearnMoreLink = injectI18n(LearnMoreLinkUi); diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/components/phase_error_message.js b/x-pack/plugins/index_lifecycle_management/public/sections/components/phase_error_message.js index 4c284494c17fb..c5fd0984ca6f3 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/components/phase_error_message.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/components/phase_error_message.js @@ -15,4 +15,4 @@ export const PhaseErrorMessage = ({ isShowingErrors }) => { /> ) : null; -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/cold_phase/cold_phase.js b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/cold_phase/cold_phase.js index 78ac8bb7c13a2..ee8759f5f6b0f 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/cold_phase/cold_phase.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/cold_phase/cold_phase.js @@ -20,10 +20,6 @@ import { import { PHASE_COLD, PHASE_ENABLED, - PHASE_ROLLOVER_ALIAS, - PHASE_ROLLOVER_MINIMUM_AGE, - PHASE_ROLLOVER_MINIMUM_AGE_UNITS, - PHASE_NODE_ATTRS, PHASE_REPLICA_COUNT, PHASE_FREEZE_ENABLED } from '../../../../store/constants'; @@ -40,15 +36,6 @@ class ColdPhaseUi extends PureComponent { isShowingErrors: PropTypes.bool.isRequired, errors: PropTypes.object.isRequired, - phaseData: PropTypes.shape({ - [PHASE_ENABLED]: PropTypes.bool.isRequired, - [PHASE_ROLLOVER_ALIAS]: PropTypes.string.isRequired, - [PHASE_ROLLOVER_MINIMUM_AGE]: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) - .isRequired, - [PHASE_ROLLOVER_MINIMUM_AGE_UNITS]: PropTypes.string.isRequired, - [PHASE_NODE_ATTRS]: PropTypes.string.isRequired, - [PHASE_REPLICA_COUNT]: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - }).isRequired, }; render() { const { @@ -100,8 +87,8 @@ class ColdPhaseUi extends PureComponent { } id={`${PHASE_COLD}-${PHASE_ENABLED}`} checked={phaseData[PHASE_ENABLED]} - onChange={async e => { - await setPhaseData(PHASE_ENABLED, e.target.checked); + onChange={e => { + setPhaseData(PHASE_ENABLED, e.target.checked); }} aria-controls="coldPhaseContent" /> @@ -157,8 +144,8 @@ class ColdPhaseUi extends PureComponent { { - await setPhaseData(PHASE_REPLICA_COUNT, e.target.value); + onChange={e => { + setPhaseData(PHASE_REPLICA_COUNT, e.target.value); }} min={0} /> @@ -197,8 +184,8 @@ class ColdPhaseUi extends PureComponent { { - await setPhaseData(PHASE_FREEZE_ENABLED, e.target.checked); + onChange={e => { + setPhaseData(PHASE_FREEZE_ENABLED, e.target.checked); }} label={freezeLabel} aria-label={freezeLabel} diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/delete_phase/delete_phase.js b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/delete_phase/delete_phase.js index 1aeee4cbb4d50..a10ae5ab65595 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/delete_phase/delete_phase.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/delete_phase/delete_phase.js @@ -19,8 +19,6 @@ import { import { PHASE_DELETE, PHASE_ENABLED, - PHASE_ROLLOVER_MINIMUM_AGE, - PHASE_ROLLOVER_MINIMUM_AGE_UNITS, } from '../../../../store/constants'; import { ActiveBadge, PhaseErrorMessage } from '../../../components'; @@ -29,14 +27,6 @@ export class DeletePhase extends PureComponent { setPhaseData: PropTypes.func.isRequired, isShowingErrors: PropTypes.bool.isRequired, errors: PropTypes.object.isRequired, - phaseData: PropTypes.shape({ - [PHASE_ENABLED]: PropTypes.bool.isRequired, - [PHASE_ROLLOVER_MINIMUM_AGE]: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string - ]).isRequired, - [PHASE_ROLLOVER_MINIMUM_AGE_UNITS]: PropTypes.string.isRequired - }).isRequired }; render() { @@ -85,8 +75,8 @@ export class DeletePhase extends PureComponent { } id={`${PHASE_DELETE}-${PHASE_ENABLED}`} checked={phaseData[PHASE_ENABLED]} - onChange={async e => { - await setPhaseData(PHASE_ENABLED, e.target.checked); + onChange={e => { + setPhaseData(PHASE_ENABLED, e.target.checked); }} aria-controls="deletePhaseContent" /> diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/hot_phase/hot_phase.js b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/hot_phase/hot_phase.js index 9ebd7e9b5dd86..ccdb2a6479b15 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/hot_phase/hot_phase.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/hot_phase/hot_phase.js @@ -21,13 +21,12 @@ import { import { LearnMoreLink, ActiveBadge, PhaseErrorMessage } from '../../../components'; import { PHASE_HOT, - PHASE_ROLLOVER_ALIAS, PHASE_ROLLOVER_MAX_AGE, PHASE_ROLLOVER_MAX_AGE_UNITS, + PHASE_ROLLOVER_MAX_DOCUMENTS, PHASE_ROLLOVER_MAX_SIZE_STORED, PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS, PHASE_ROLLOVER_ENABLED, - MAX_SIZE_TYPE_DOCUMENT } from '../../../../store/constants'; import { SetPriorityInput } from '../set_priority_input'; @@ -39,19 +38,6 @@ class HotPhaseUi extends PureComponent { isShowingErrors: PropTypes.bool.isRequired, errors: PropTypes.object.isRequired, - phaseData: PropTypes.shape({ - [PHASE_ROLLOVER_ALIAS]: PropTypes.string.isRequired, - [PHASE_ROLLOVER_MAX_AGE]: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string - ]).isRequired, - [PHASE_ROLLOVER_MAX_AGE_UNITS]: PropTypes.string.isRequired, - [PHASE_ROLLOVER_MAX_SIZE_STORED]: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string - ]).isRequired, - [PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS]: PropTypes.string.isRequired - }).isRequired }; render() { @@ -63,7 +49,6 @@ class HotPhaseUi extends PureComponent { intl, setWarmPhaseOnRollover } = this.props; - return ( { - await setPhaseData( + onChange={e => { + setPhaseData( PHASE_ROLLOVER_MAX_SIZE_STORED, e.target.value ); @@ -174,8 +159,8 @@ class HotPhaseUi extends PureComponent { defaultMessage: 'Maximum index size units' })} value={phaseData[PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS]} - onChange={async e => { - await setPhaseData( + onChange={e => { + setPhaseData( PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS, e.target.value ); @@ -185,9 +170,9 @@ class HotPhaseUi extends PureComponent { id: 'xpack.indexLifecycleMgmt.hotPhase.gigabytesLabel', defaultMessage: 'gigabytes' }) }, - { value: MAX_SIZE_TYPE_DOCUMENT, text: intl.formatMessage({ - id: 'xpack.indexLifecycleMgmt.hotPhase.documentsLabel', - defaultMessage: 'documents' + { value: 'mb', text: intl.formatMessage({ + id: 'xpack.indexLifecycleMgmt.hotPhase.megabytesLabel', + defaultMessage: 'megabytes' }) } ]} /> @@ -195,6 +180,33 @@ class HotPhaseUi extends PureComponent { + + + + { + setPhaseData( + PHASE_ROLLOVER_MAX_DOCUMENTS, + e.target.value + ); + }} + min={1} + /> + + + + { - await setPhaseData(PHASE_ROLLOVER_MAX_AGE, e.target.value); + onChange={e => { + setPhaseData(PHASE_ROLLOVER_MAX_AGE, e.target.value); }} min={1} /> @@ -231,8 +243,8 @@ class HotPhaseUi extends PureComponent { defaultMessage: 'Maximum age units' })} value={phaseData[PHASE_ROLLOVER_MAX_AGE_UNITS]} - onChange={async e => { - await setPhaseData( + onChange={e => { + setPhaseData( PHASE_ROLLOVER_MAX_AGE_UNITS, e.target.value ); diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/node_allocation/index.js b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/node_allocation/index.js index dcf6a0787755d..9138c6a30cfad 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/node_allocation/index.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/node_allocation/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { NodeAllocation } from './node_allocation.container'; \ No newline at end of file +export { NodeAllocation } from './node_allocation.container'; diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/node_allocation/node_allocation.js b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/node_allocation/node_allocation.js index a6b3eaf02ee60..60f37c4be7296 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/node_allocation/node_allocation.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/node_allocation/node_allocation.js @@ -88,8 +88,8 @@ class NodeAllocationUi extends Component { id={`${phase}-${PHASE_NODE_ATTRS}`} value={phaseData[PHASE_NODE_ATTRS] || ' '} options={nodeOptions} - onChange={async e => { - await setPhaseData(PHASE_NODE_ATTRS, e.target.value); + onChange={e => { + setPhaseData(PHASE_NODE_ATTRS, e.target.value); }} /> diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/set_priority_input.js b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/set_priority_input.js index 4ca792e3bbdd5..af65348171957 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/set_priority_input.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/set_priority_input.js @@ -59,12 +59,12 @@ export const SetPriorityInput = props => { { - await setPhaseData(PHASE_INDEX_PRIORITY, e.target.value); + onChange={e => { + setPhaseData(PHASE_INDEX_PRIORITY, e.target.value); }} min={0} /> ); -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/warm_phase/warm_phase.js b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/warm_phase/warm_phase.js index 27a756735c8fb..d9c9d0930daf9 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/warm_phase/warm_phase.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/edit_policy/components/warm_phase/warm_phase.js @@ -21,14 +21,10 @@ import { PHASE_WARM, PHASE_ENABLED, WARM_PHASE_ON_ROLLOVER, - PHASE_ROLLOVER_ALIAS, PHASE_FORCE_MERGE_ENABLED, PHASE_FORCE_MERGE_SEGMENTS, - PHASE_NODE_ATTRS, PHASE_PRIMARY_SHARD_COUNT, PHASE_REPLICA_COUNT, - PHASE_ROLLOVER_MINIMUM_AGE, - PHASE_ROLLOVER_MINIMUM_AGE_UNITS, PHASE_SHRINK_ENABLED, } from '../../../../store/constants'; import { SetPriorityInput } from '../set_priority_input'; @@ -43,21 +39,6 @@ class WarmPhaseUi extends PureComponent { isShowingErrors: PropTypes.bool.isRequired, errors: PropTypes.object.isRequired, - phaseData: PropTypes.shape({ - [PHASE_ENABLED]: PropTypes.bool.isRequired, - [WARM_PHASE_ON_ROLLOVER]: PropTypes.bool.isRequired, - [PHASE_ROLLOVER_ALIAS]: PropTypes.string.isRequired, - [PHASE_FORCE_MERGE_ENABLED]: PropTypes.bool.isRequired, - [PHASE_FORCE_MERGE_SEGMENTS]: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) - .isRequired, - [PHASE_NODE_ATTRS]: PropTypes.string.isRequired, - [PHASE_PRIMARY_SHARD_COUNT]: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) - .isRequired, - [PHASE_REPLICA_COUNT]: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - [PHASE_ROLLOVER_MINIMUM_AGE]: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) - .isRequired, - [PHASE_ROLLOVER_MINIMUM_AGE_UNITS]: PropTypes.string.isRequired, - }).isRequired, }; render() { const { @@ -117,8 +98,8 @@ class WarmPhaseUi extends PureComponent { } id={`${PHASE_WARM}-${PHASE_ENABLED}`} checked={phaseData[PHASE_ENABLED]} - onChange={async e => { - await setPhaseData(PHASE_ENABLED, e.target.checked); + onChange={e => { + setPhaseData(PHASE_ENABLED, e.target.checked); }} aria-controls="warmPhaseContent" /> @@ -138,8 +119,8 @@ class WarmPhaseUi extends PureComponent { label={moveToWarmPhaseOnRolloverLabel} id={`${PHASE_WARM}-${WARM_PHASE_ON_ROLLOVER}`} checked={phaseData[WARM_PHASE_ON_ROLLOVER]} - onChange={async e => { - await setPhaseData(WARM_PHASE_ON_ROLLOVER, e.target.checked); + onChange={e => { + setPhaseData(WARM_PHASE_ON_ROLLOVER, e.target.checked); }} /> @@ -192,8 +173,8 @@ class WarmPhaseUi extends PureComponent { { - await setPhaseData(PHASE_REPLICA_COUNT, e.target.value); + onChange={e => { + setPhaseData(PHASE_REPLICA_COUNT, e.target.value); }} min={0} /> @@ -233,8 +214,8 @@ class WarmPhaseUi extends PureComponent { { - await setPhaseData(PHASE_SHRINK_ENABLED, e.target.checked); + onChange={e => { + setPhaseData(PHASE_SHRINK_ENABLED, e.target.checked); }} label={shrinkLabel} aria-label={shrinkLabel} @@ -259,8 +240,8 @@ class WarmPhaseUi extends PureComponent { { - await setPhaseData(PHASE_PRIMARY_SHARD_COUNT, e.target.value); + onChange={e => { + setPhaseData(PHASE_PRIMARY_SHARD_COUNT, e.target.value); }} min={1} /> @@ -299,8 +280,8 @@ class WarmPhaseUi extends PureComponent { label={forcemergeLabel} aria-label={forcemergeLabel} checked={phaseData[PHASE_FORCE_MERGE_ENABLED]} - onChange={async e => { - await setPhaseData(PHASE_FORCE_MERGE_ENABLED, e.target.checked); + onChange={e => { + setPhaseData(PHASE_FORCE_MERGE_ENABLED, e.target.checked); }} aria-controls="forcemergeContent" /> @@ -321,8 +302,8 @@ class WarmPhaseUi extends PureComponent { { - await setPhaseData(PHASE_FORCE_MERGE_SEGMENTS, e.target.value); + onChange={e => { + setPhaseData(PHASE_FORCE_MERGE_SEGMENTS, e.target.value); }} min={1} /> diff --git a/x-pack/plugins/index_lifecycle_management/public/sections/policy_table/components/policy_table/index.js b/x-pack/plugins/index_lifecycle_management/public/sections/policy_table/components/policy_table/index.js index 1e10c49443cef..81bdb065ef4a0 100644 --- a/x-pack/plugins/index_lifecycle_management/public/sections/policy_table/components/policy_table/index.js +++ b/x-pack/plugins/index_lifecycle_management/public/sections/policy_table/components/policy_table/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { PolicyTable } from './policy_table.container'; \ No newline at end of file +export { PolicyTable } from './policy_table.container'; diff --git a/x-pack/plugins/index_lifecycle_management/public/services/index.js b/x-pack/plugins/index_lifecycle_management/public/services/index.js index 86f51d8b4a4c1..a82b581309d29 100644 --- a/x-pack/plugins/index_lifecycle_management/public/services/index.js +++ b/x-pack/plugins/index_lifecycle_management/public/services/index.js @@ -5,4 +5,4 @@ */ export { filterItems } from './filter_items'; -export { sortTable } from './sort_table'; \ No newline at end of file +export { sortTable } from './sort_table'; diff --git a/x-pack/plugins/index_lifecycle_management/public/services/navigation.js b/x-pack/plugins/index_lifecycle_management/public/services/navigation.js index 655d9cf6608ff..7a396b740ec01 100644 --- a/x-pack/plugins/index_lifecycle_management/public/services/navigation.js +++ b/x-pack/plugins/index_lifecycle_management/public/services/navigation.js @@ -20,4 +20,4 @@ export const goToPolicyList = () => { export const getPolicyPath = (policyName) => { return encodeURI(`#${BASE_PATH}policies/edit/${encodeURIComponent(policyName)}`); -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/store/constants.js b/x-pack/plugins/index_lifecycle_management/public/store/constants.js index d01a17b3e34e8..decf1c86942ae 100644 --- a/x-pack/plugins/index_lifecycle_management/public/store/constants.js +++ b/x-pack/plugins/index_lifecycle_management/public/store/constants.js @@ -13,14 +13,13 @@ export const PHASE_DELETE = 'delete'; export const PHASE_ENABLED = 'phaseEnabled'; -export const MAX_SIZE_TYPE_DOCUMENT = 'd'; - export const PHASE_ROLLOVER_ENABLED = 'rolloverEnabled'; export const WARM_PHASE_ON_ROLLOVER = 'warmPhaseOnRollover'; export const PHASE_ROLLOVER_ALIAS = 'selectedAlias'; export const PHASE_ROLLOVER_MAX_AGE = 'selectedMaxAge'; export const PHASE_ROLLOVER_MAX_AGE_UNITS = 'selectedMaxAgeUnits'; export const PHASE_ROLLOVER_MAX_SIZE_STORED = 'selectedMaxSizeStored'; +export const PHASE_ROLLOVER_MAX_DOCUMENTS = 'selectedMaxDocuments'; export const PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS = 'selectedMaxSizeStoredUnits'; export const PHASE_ROLLOVER_MINIMUM_AGE = 'selectedMinimumAge'; export const PHASE_ROLLOVER_MINIMUM_AGE_UNITS = 'selectedMinimumAgeUnits'; @@ -47,6 +46,7 @@ export const PHASE_ATTRIBUTES_THAT_ARE_NUMBERS = [ ...PHASE_ATTRIBUTES_THAT_ARE_NUMBERS_VALIDATE, PHASE_ROLLOVER_MAX_AGE, PHASE_ROLLOVER_MAX_SIZE_STORED, + PHASE_ROLLOVER_MAX_DOCUMENTS ]; export const STRUCTURE_INDEX_TEMPLATE = 'indexTemplate'; @@ -70,6 +70,7 @@ export const ERROR_STRUCTURE = { [PHASE_ROLLOVER_MAX_AGE]: [], [PHASE_ROLLOVER_MAX_AGE_UNITS]: [], [PHASE_ROLLOVER_MAX_SIZE_STORED]: [], + [PHASE_ROLLOVER_MAX_DOCUMENTS]: [], [PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS]: [], [PHASE_INDEX_PRIORITY]: [] }, diff --git a/x-pack/plugins/index_lifecycle_management/public/store/defaults/cold_phase.js b/x-pack/plugins/index_lifecycle_management/public/store/defaults/cold_phase.js index c749b08fdaa68..0a4f4e2206d65 100644 --- a/x-pack/plugins/index_lifecycle_management/public/store/defaults/cold_phase.js +++ b/x-pack/plugins/index_lifecycle_management/public/store/defaults/cold_phase.js @@ -23,4 +23,8 @@ export const defaultColdPhase = { [PHASE_REPLICA_COUNT]: '', [PHASE_FREEZE_ENABLED]: false, [PHASE_INDEX_PRIORITY]: 0 -}; \ No newline at end of file +}; +export const defaultEmptyColdPhase = { + ...defaultColdPhase, + [PHASE_INDEX_PRIORITY]: '' +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/store/defaults/delete_phase.js b/x-pack/plugins/index_lifecycle_management/public/store/defaults/delete_phase.js index e5326615e536a..c449ba073fd24 100644 --- a/x-pack/plugins/index_lifecycle_management/public/store/defaults/delete_phase.js +++ b/x-pack/plugins/index_lifecycle_management/public/store/defaults/delete_phase.js @@ -17,4 +17,5 @@ export const defaultDeletePhase = { [PHASE_ROLLOVER_ALIAS]: '', [PHASE_ROLLOVER_MINIMUM_AGE]: '', [PHASE_ROLLOVER_MINIMUM_AGE_UNITS]: 'd' -}; \ No newline at end of file +}; +export const defaultEmptyDeletePhase = defaultDeletePhase; diff --git a/x-pack/plugins/index_lifecycle_management/public/store/defaults/hot_phase.js b/x-pack/plugins/index_lifecycle_management/public/store/defaults/hot_phase.js index dcbf2f38ab964..43ffc1b565e5b 100644 --- a/x-pack/plugins/index_lifecycle_management/public/store/defaults/hot_phase.js +++ b/x-pack/plugins/index_lifecycle_management/public/store/defaults/hot_phase.js @@ -9,18 +9,27 @@ import { PHASE_ROLLOVER_MAX_AGE, PHASE_ROLLOVER_MAX_AGE_UNITS, PHASE_ROLLOVER_MAX_SIZE_STORED, + PHASE_ROLLOVER_MAX_DOCUMENTS, PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS, - PHASE_ROLLOVER_ALIAS, PHASE_INDEX_PRIORITY } from '../constants'; export const defaultHotPhase = { [PHASE_ENABLED]: true, [PHASE_ROLLOVER_ENABLED]: true, - [PHASE_ROLLOVER_ALIAS]: '', [PHASE_ROLLOVER_MAX_AGE]: 30, [PHASE_ROLLOVER_MAX_AGE_UNITS]: 'd', [PHASE_ROLLOVER_MAX_SIZE_STORED]: 50, [PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS]: 'gb', - [PHASE_INDEX_PRIORITY]: 100 -}; \ No newline at end of file + [PHASE_INDEX_PRIORITY]: 100, + [PHASE_ROLLOVER_MAX_DOCUMENTS]: '' +}; +export const defaultEmptyHotPhase = { + ...defaultHotPhase, + [PHASE_ENABLED]: false, + [PHASE_ROLLOVER_ENABLED]: false, + [PHASE_ROLLOVER_MAX_AGE]: '', + [PHASE_ROLLOVER_MAX_SIZE_STORED]: '', + [PHASE_INDEX_PRIORITY]: '', + [PHASE_ROLLOVER_MAX_DOCUMENTS]: '' +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/store/defaults/index.js b/x-pack/plugins/index_lifecycle_management/public/store/defaults/index.js index a92f98fa8e022..f5661eae91a8c 100644 --- a/x-pack/plugins/index_lifecycle_management/public/store/defaults/index.js +++ b/x-pack/plugins/index_lifecycle_management/public/store/defaults/index.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -export { defaultDeletePhase } from './delete_phase'; -export { defaultColdPhase } from './cold_phase'; -export { defaultHotPhase } from './hot_phase'; -export { defaultWarmPhase } from './warm_phase'; \ No newline at end of file +export * from './delete_phase'; +export * from './cold_phase'; +export * from './hot_phase'; +export * from './warm_phase'; diff --git a/x-pack/plugins/index_lifecycle_management/public/store/defaults/warm_phase.js b/x-pack/plugins/index_lifecycle_management/public/store/defaults/warm_phase.js index cda788e0c1a1b..8e55b5c72c4f0 100644 --- a/x-pack/plugins/index_lifecycle_management/public/store/defaults/warm_phase.js +++ b/x-pack/plugins/index_lifecycle_management/public/store/defaults/warm_phase.js @@ -31,4 +31,9 @@ export const defaultWarmPhase = { [PHASE_REPLICA_COUNT]: '', [WARM_PHASE_ON_ROLLOVER]: true, [PHASE_INDEX_PRIORITY]: 50 -}; \ No newline at end of file +}; +export const defaultEmptyWarmPhase = { + ...defaultWarmPhase, + [WARM_PHASE_ON_ROLLOVER]: false, + [PHASE_INDEX_PRIORITY]: '' +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/store/selectors/lifecycle.js b/x-pack/plugins/index_lifecycle_management/public/store/selectors/lifecycle.js index dca6468abe66c..a25299d54675a 100644 --- a/x-pack/plugins/index_lifecycle_management/public/store/selectors/lifecycle.js +++ b/x-pack/plugins/index_lifecycle_management/public/store/selectors/lifecycle.js @@ -23,7 +23,8 @@ import { PHASE_FORCE_MERGE_SEGMENTS, PHASE_REPLICA_COUNT, WARM_PHASE_ON_ROLLOVER, - PHASE_INDEX_PRIORITY + PHASE_INDEX_PRIORITY, + PHASE_ROLLOVER_MAX_DOCUMENTS } from '../constants'; import { getPhase, @@ -49,6 +50,10 @@ export const maximumSizeRequiredMessage = i18n.translate('xpack.indexLifecycleMgmt.editPolicy.maximumIndexSizeMissingError', { defaultMessage: 'A maximum index size is required.' }); +export const maximumDocumentsRequiredMessage = + i18n.translate('xpack.indexLifecycleMgmt.editPolicy.maximumDocumentsMissingError', { + defaultMessage: 'Maximum documents is required.' + }); export const positiveNumbersAboveZeroErrorMessage = i18n.translate('xpack.indexLifecycleMgmt.editPolicy.positiveNumberAboveZeroRequiredError', { defaultMessage: 'Only numbers above 0 are allowed.' @@ -97,8 +102,9 @@ export const validatePhase = (type, phase, errors) => { } if (phase[PHASE_ROLLOVER_ENABLED]) { if ( - !isNumber(phase[PHASE_ROLLOVER_MAX_AGE]) && - !isNumber(phase[PHASE_ROLLOVER_MAX_SIZE_STORED]) + !isNumber(phase[PHASE_ROLLOVER_MAX_AGE]) + && !isNumber(phase[PHASE_ROLLOVER_MAX_SIZE_STORED]) + && !isNumber(phase[PHASE_ROLLOVER_MAX_DOCUMENTS]) ) { phaseErrors[PHASE_ROLLOVER_MAX_AGE] = [ maximumAgeRequiredMessage @@ -106,6 +112,9 @@ export const validatePhase = (type, phase, errors) => { phaseErrors[PHASE_ROLLOVER_MAX_SIZE_STORED] = [ maximumSizeRequiredMessage ]; + phaseErrors[PHASE_ROLLOVER_MAX_DOCUMENTS] = [ + maximumDocumentsRequiredMessage + ]; } if (isNumber(phase[PHASE_ROLLOVER_MAX_AGE]) && phase[PHASE_ROLLOVER_MAX_AGE] < 1) { phaseErrors[PHASE_ROLLOVER_MAX_AGE] = [ @@ -117,6 +126,11 @@ export const validatePhase = (type, phase, errors) => { positiveNumbersAboveZeroErrorMessage ]; } + if (isNumber(phase[PHASE_ROLLOVER_MAX_DOCUMENTS]) && phase[PHASE_ROLLOVER_MAX_DOCUMENTS] < 1) { + phaseErrors[PHASE_ROLLOVER_MAX_DOCUMENTS] = [ + positiveNumbersAboveZeroErrorMessage + ]; + } } if (phase[PHASE_SHRINK_ENABLED]) { if (!isNumber(phase[PHASE_PRIMARY_SHARD_COUNT])) { diff --git a/x-pack/plugins/index_lifecycle_management/public/store/selectors/policies.js b/x-pack/plugins/index_lifecycle_management/public/store/selectors/policies.js index f41a6cf7d2e33..30649e8a62042 100644 --- a/x-pack/plugins/index_lifecycle_management/public/store/selectors/policies.js +++ b/x-pack/plugins/index_lifecycle_management/public/store/selectors/policies.js @@ -8,12 +8,6 @@ import { createSelector } from 'reselect'; import { Pager } from '@elastic/eui'; -import { - defaultColdPhase, - defaultDeletePhase, - defaultHotPhase, - defaultWarmPhase, -} from '../defaults'; import { PHASE_HOT, PHASE_WARM, @@ -33,12 +27,18 @@ import { PHASE_REPLICA_COUNT, PHASE_ENABLED, PHASE_ATTRIBUTES_THAT_ARE_NUMBERS, - MAX_SIZE_TYPE_DOCUMENT, WARM_PHASE_ON_ROLLOVER, PHASE_SHRINK_ENABLED, PHASE_FREEZE_ENABLED, - PHASE_INDEX_PRIORITY + PHASE_INDEX_PRIORITY, + PHASE_ROLLOVER_MAX_DOCUMENTS } from '../constants'; +import { + defaultEmptyDeletePhase, + defaultEmptyColdPhase, + defaultEmptyWarmPhase, + defaultEmptyHotPhase +} from '../defaults'; import { filterItems, sortTable } from '../../services'; @@ -127,15 +127,14 @@ export const isEmptyObject = (obj) => { return Object.entries(obj).length === 0 && obj.constructor === Object; }; -export const phaseFromES = (phase, phaseName, defaultPolicy) => { - const policy = { ...defaultPolicy }; - +export const phaseFromES = (phase, phaseName, defaultEmptyPolicy) => { + const policy = { ...defaultEmptyPolicy }; if (!phase) { return policy; } policy[PHASE_ENABLED] = true; - policy[PHASE_ROLLOVER_ENABLED] = false; + if (phase.min_age) { if (phaseName === PHASE_WARM && phase.min_age === '0ms') { @@ -149,7 +148,8 @@ export const phaseFromES = (phase, phaseName, defaultPolicy) => { } } if (phaseName === PHASE_WARM) { - policy[PHASE_SHRINK_ENABLED] = !!(phase.actions && phase.actions.shrink); + policy[PHASE_SHRINK_ENABLED] = false; + policy[PHASE_FORCE_MERGE_ENABLED] = false; } if (phase.actions) { const actions = phase.actions; @@ -172,8 +172,7 @@ export const phaseFromES = (phase, phaseName, defaultPolicy) => { policy[PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS] = maxSizeUnits; } if (rollover.max_docs) { - policy[PHASE_ROLLOVER_MAX_SIZE_STORED] = rollover.max_docs; - policy[PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS] = MAX_SIZE_TYPE_DOCUMENT; + policy[PHASE_ROLLOVER_MAX_DOCUMENTS] = rollover.max_docs; } } @@ -214,10 +213,10 @@ export const policyFromES = (policy) => { return { name, phases: { - [PHASE_HOT]: phaseFromES(phases[PHASE_HOT], PHASE_HOT, defaultHotPhase), - [PHASE_WARM]: phaseFromES(phases[PHASE_WARM], PHASE_WARM, defaultWarmPhase), - [PHASE_COLD]: phaseFromES(phases[PHASE_COLD], PHASE_COLD, defaultColdPhase), - [PHASE_DELETE]: phaseFromES(phases[PHASE_DELETE], PHASE_DELETE, defaultDeletePhase) + [PHASE_HOT]: phaseFromES(phases[PHASE_HOT], PHASE_HOT, defaultEmptyHotPhase), + [PHASE_WARM]: phaseFromES(phases[PHASE_WARM], PHASE_WARM, defaultEmptyWarmPhase), + [PHASE_COLD]: phaseFromES(phases[PHASE_COLD], PHASE_COLD, defaultEmptyColdPhase), + [PHASE_DELETE]: phaseFromES(phases[PHASE_DELETE], PHASE_DELETE, defaultEmptyDeletePhase) }, isNew: false, saveAsNew: false @@ -245,13 +244,12 @@ export const phaseToES = (phase, originalEsPhase) => { }`; } if (isNumber(phase[PHASE_ROLLOVER_MAX_SIZE_STORED])) { - if (phase[PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS] === MAX_SIZE_TYPE_DOCUMENT) { - esPhase.actions.rollover.max_docs = phase[PHASE_ROLLOVER_MAX_SIZE_STORED]; - } else { - esPhase.actions.rollover.max_size = `${phase[PHASE_ROLLOVER_MAX_SIZE_STORED]}${ - phase[PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS] - }`; - } + esPhase.actions.rollover.max_size = `${phase[PHASE_ROLLOVER_MAX_SIZE_STORED]}${ + phase[PHASE_ROLLOVER_MAX_SIZE_STORED_UNITS] + }`; + } + if (isNumber(phase[PHASE_ROLLOVER_MAX_DOCUMENTS])) { + esPhase.actions.rollover.max_docs = phase[PHASE_ROLLOVER_MAX_DOCUMENTS]; } } else { delete esPhase.actions.rollover; diff --git a/x-pack/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_unknown_error.js b/x-pack/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_unknown_error.js index 4b865880ae20d..ffd915c513362 100644 --- a/x-pack/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_unknown_error.js +++ b/x-pack/plugins/index_lifecycle_management/server/lib/error_wrappers/wrap_unknown_error.js @@ -14,4 +14,4 @@ import Boom from 'boom'; */ export function wrapUnknownError(err) { return Boom.boomify(err); -} \ No newline at end of file +} diff --git a/x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js b/x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js index 6cedc82e2291e..3642de5ffabb1 100644 --- a/x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js +++ b/x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js @@ -30,4 +30,4 @@ describe('flatten_object', () => { }; expect(flattenObject(obj)).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/index_management/__mocks__/ui/documentation_links.js b/x-pack/plugins/index_management/__mocks__/ui/documentation_links.js index ac606ca67aad9..0da03ba9b98ba 100644 --- a/x-pack/plugins/index_management/__mocks__/ui/documentation_links.js +++ b/x-pack/plugins/index_management/__mocks__/ui/documentation_links.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export const settingsDocumentationLink = 'https://stuff.com/docs'; \ No newline at end of file +export const settingsDocumentationLink = 'https://stuff.com/docs'; diff --git a/x-pack/plugins/index_management/__mocks__/ui/notify.js b/x-pack/plugins/index_management/__mocks__/ui/notify.js index de39a97977200..8d61b9be5409b 100644 --- a/x-pack/plugins/index_management/__mocks__/ui/notify.js +++ b/x-pack/plugins/index_management/__mocks__/ui/notify.js @@ -7,4 +7,4 @@ export const toastNotifications = { addSuccess: () => {}, addDanger: () => {}, -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/index_management/common/constants/plugin.js b/x-pack/plugins/index_management/common/constants/plugin.js index 42c4630e73b77..3334751ecd058 100644 --- a/x-pack/plugins/index_management/common/constants/plugin.js +++ b/x-pack/plugins/index_management/common/constants/plugin.js @@ -4,6 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; + export const PLUGIN = { - ID: 'index_management' + ID: 'index_management', + NAME: i18n.translate('xpack.idxMgmt.appTitle', { + defaultMessage: 'Index Management' + }), + MINIMUM_LICENSE_REQUIRED: 'basic', }; diff --git a/x-pack/plugins/index_management/index.js b/x-pack/plugins/index_management/index.js index 472847f664708..d0910ec9ce703 100644 --- a/x-pack/plugins/index_management/index.js +++ b/x-pack/plugins/index_management/index.js @@ -29,7 +29,7 @@ export function indexManagement(kibana) { init: function (server) { const router = createRouter(server, PLUGIN.ID, '/api/index_management/'); server.expose('addIndexManagementDataEnricher', addIndexManagementDataEnricher); - registerLicenseChecker(server, PLUGIN.ID); + registerLicenseChecker(server, PLUGIN.ID, PLUGIN.NAME, PLUGIN.MINIMUM_LICENSE_REQUIRED); registerIndicesRoutes(router); registerSettingsRoutes(router); registerStatsRoute(router); diff --git a/x-pack/plugins/index_management/index_management_data.js b/x-pack/plugins/index_management/index_management_data.js index 60b2ffba236de..4041a74eb611b 100644 --- a/x-pack/plugins/index_management/index_management_data.js +++ b/x-pack/plugins/index_management/index_management_data.js @@ -10,4 +10,4 @@ export const addIndexManagementDataEnricher = (enricher) => { }; export const getIndexManagementDataEnrichers = () => { return indexManagementDataEnrichers; -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/index_management/public/lib/editSettings.js b/x-pack/plugins/index_management/public/lib/editSettings.js index 34387a277c54b..4caa371e0d286 100644 --- a/x-pack/plugins/index_management/public/lib/editSettings.js +++ b/x-pack/plugins/index_management/public/lib/editSettings.js @@ -29,4 +29,4 @@ export const settingsToDisplay = [ 'index.query.default_field', 'index.refresh_interval', 'index.write.wait_for_active_shards' -]; \ No newline at end of file +]; diff --git a/x-pack/plugins/index_management/public/lib/flatten_object.js b/x-pack/plugins/index_management/public/lib/flatten_object.js index 54cf0e56a071d..7e84bd49f93df 100644 --- a/x-pack/plugins/index_management/public/lib/flatten_object.js +++ b/x-pack/plugins/index_management/public/lib/flatten_object.js @@ -20,4 +20,4 @@ export const flattenObject = (nestedObj, flattenArrays) => { }); }(nestedObj)); return flatObj; -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/index_management/public/lib/render_badges.js b/x-pack/plugins/index_management/public/lib/render_badges.js index 6803ecff31c92..bd8cb92d42114 100644 --- a/x-pack/plugins/index_management/public/lib/render_badges.js +++ b/x-pack/plugins/index_management/public/lib/render_badges.js @@ -44,4 +44,4 @@ export const renderBadges = (index, filterChanged) => { {badgeLabels} ); -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/edit_settings_json/index.js b/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/edit_settings_json/index.js index 6fb82a65dde80..3125ca94c3018 100644 --- a/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/edit_settings_json/index.js +++ b/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/edit_settings_json/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EditSettingsJson } from './edit_settings_json.container'; \ No newline at end of file +export { EditSettingsJson } from './edit_settings_json.container'; diff --git a/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/index.js b/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/index.js index bdc6607efc1d3..c27bbd8ea830f 100644 --- a/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/index.js +++ b/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { DetailPanel } from './detail_panel.container'; \ No newline at end of file +export { DetailPanel } from './detail_panel.container'; diff --git a/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/show_json/index.js b/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/show_json/index.js index 22f4edc9912de..2679651307ff7 100644 --- a/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/show_json/index.js +++ b/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/show_json/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ShowJson } from './show_json.container'; \ No newline at end of file +export { ShowJson } from './show_json.container'; diff --git a/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/summary/index.js b/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/summary/index.js index d979e95ff7866..64f543640bda0 100644 --- a/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/summary/index.js +++ b/x-pack/plugins/index_management/public/sections/index_list/components/detail_panel/summary/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { Summary } from './summary.container'; \ No newline at end of file +export { Summary } from './summary.container'; diff --git a/x-pack/plugins/index_management/public/services/api.js b/x-pack/plugins/index_management/public/services/api.js index 8b7347864e481..c8d77f140db61 100644 --- a/x-pack/plugins/index_management/public/services/api.js +++ b/x-pack/plugins/index_management/public/services/api.js @@ -126,4 +126,4 @@ export async function loadIndexData(type, indexName) { case 'Stats': return loadIndexStats(indexName); } -} \ No newline at end of file +} diff --git a/x-pack/plugins/index_management/public/store/actions/table_state.js b/x-pack/plugins/index_management/public/store/actions/table_state.js index e72b116a5595e..d693cab5478bf 100644 --- a/x-pack/plugins/index_management/public/store/actions/table_state.js +++ b/x-pack/plugins/index_management/public/store/actions/table_state.js @@ -25,4 +25,4 @@ export const showSystemIndicesChanged = createAction('INDEX_MANAGEMENT_SHOW_SYSTEM_INDICES_CHANGED'); export const toggleChanged = - createAction('INDEX_MANAGEMENT_TOGGLE_CHANGED'); \ No newline at end of file + createAction('INDEX_MANAGEMENT_TOGGLE_CHANGED'); diff --git a/x-pack/plugins/index_management/public/store/reducers/detail_panel.js b/x-pack/plugins/index_management/public/store/reducers/detail_panel.js index d8c1bdbd2d105..41105b745693e 100644 --- a/x-pack/plugins/index_management/public/store/reducers/detail_panel.js +++ b/x-pack/plugins/index_management/public/store/reducers/detail_panel.js @@ -59,4 +59,4 @@ export const detailPanel = handleActions( }, }, defaultState -); \ No newline at end of file +); diff --git a/x-pack/plugins/index_management/public/store/reducers/index_management.js b/x-pack/plugins/index_management/public/store/reducers/index_management.js index 871c130e91a1c..1dfc12caea2ad 100644 --- a/x-pack/plugins/index_management/public/store/reducers/index_management.js +++ b/x-pack/plugins/index_management/public/store/reducers/index_management.js @@ -15,4 +15,4 @@ export const indexManagement = combineReducers({ rowStatus, tableState, detailPanel -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/index_management/public/store/reducers/table_state.js b/x-pack/plugins/index_management/public/store/reducers/table_state.js index 709237e0cea9e..e3af9414b5eb2 100644 --- a/x-pack/plugins/index_management/public/store/reducers/table_state.js +++ b/x-pack/plugins/index_management/public/store/reducers/table_state.js @@ -38,7 +38,6 @@ export const tableState = handleActions({ return { ...state, showSystemIndices, - toggleNameToVisibleMap: {} }; }, [toggleChanged](state, action) { diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.js b/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.js index 9999475a9a2ca..90b933c070cd3 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.js +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.js @@ -17,4 +17,4 @@ const handler = async (request, callWithRequest, h) => { }; export function registerFlushRoute(router) { router.post('indices/flush', handler); -} \ No newline at end of file +} diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.js b/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.js index 8f9b749448a23..bffb8a8eb8391 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.js +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.js @@ -20,4 +20,4 @@ const handler = async (request, callWithRequest, h) => { }; export function registerForcemergeRoute(router) { router.post('indices/forcemerge', handler); -} \ No newline at end of file +} diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.js b/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.js index 5fbfe430e376f..6c83b806113b5 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.js +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.js @@ -10,4 +10,4 @@ const handler = async (request, callWithRequest) => { }; export function registerListRoute(router) { router.get('indices', handler); -} \ No newline at end of file +} diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.js b/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.js index a7ee59dd1b603..1d1bfe52f92d4 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.js +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.js @@ -17,4 +17,4 @@ const handler = async (request, callWithRequest, h) => { }; export function registerRefreshRoute(router) { router.post('indices/refresh', handler); -} \ No newline at end of file +} diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_unfreeze_route.js b/x-pack/plugins/index_management/server/routes/api/indices/register_unfreeze_route.js index 02957dbe80967..dc3f7eeed013d 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_unfreeze_route.js +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_unfreeze_route.js @@ -17,4 +17,4 @@ const handler = async (request, callWithRequest, h) => { }; export function registerUnfreezeRoute(router) { router.post('indices/unfreeze', handler); -} \ No newline at end of file +} diff --git a/x-pack/plugins/index_management/server/routes/api/mapping/index.js b/x-pack/plugins/index_management/server/routes/api/mapping/index.js index 81d9be047f495..905a6d366a25d 100644 --- a/x-pack/plugins/index_management/server/routes/api/mapping/index.js +++ b/x-pack/plugins/index_management/server/routes/api/mapping/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { registerMappingRoute } from './register_mapping_route'; \ No newline at end of file +export { registerMappingRoute } from './register_mapping_route'; diff --git a/x-pack/plugins/index_management/server/routes/api/settings/register_update_route.js b/x-pack/plugins/index_management/server/routes/api/settings/register_update_route.js index f90d4ce7b3d8d..86aacd8a6154c 100644 --- a/x-pack/plugins/index_management/server/routes/api/settings/register_update_route.js +++ b/x-pack/plugins/index_management/server/routes/api/settings/register_update_route.js @@ -19,4 +19,4 @@ const handler = async (request, callWithRequest) => { }; export function registerUpdateRoute(router) { router.put('settings/{indexName}', handler); -} \ No newline at end of file +} diff --git a/x-pack/plugins/index_management/server/routes/api/stats/index.js b/x-pack/plugins/index_management/server/routes/api/stats/index.js index 14f92e429b543..abc5e1f19b805 100644 --- a/x-pack/plugins/index_management/server/routes/api/stats/index.js +++ b/x-pack/plugins/index_management/server/routes/api/stats/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { registerStatsRoute } from './register_stats_route'; \ No newline at end of file +export { registerStatsRoute } from './register_stats_route'; diff --git a/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.js b/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.js index 538f5a6e62859..a80c0cee92334 100644 --- a/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.js +++ b/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.js @@ -27,4 +27,4 @@ const handler = async (request, callWithRequest) => { }; export function registerStatsRoute(router) { router.get('stats/{indexName}', handler); -} \ No newline at end of file +} diff --git a/x-pack/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/plugins/infra/public/components/nodes_overview/table.tsx index 65bd017d5209f..d7faccb7be81a 100644 --- a/x-pack/plugins/infra/public/components/nodes_overview/table.tsx +++ b/x-pack/plugins/infra/public/components/nodes_overview/table.tsx @@ -124,7 +124,7 @@ export const TableView = injectI18n( const items = nodes.map(node => { const name = last(node.path); return { - name: (name && name.value) || 'unknown', + name: (name && name.label) || 'unknown', ...getGroupPaths(node.path).reduce( (acc, path, index) => ({ ...acc, diff --git a/x-pack/plugins/infra/public/components/range_date_picker/index.tsx b/x-pack/plugins/infra/public/components/range_date_picker/index.tsx index 4abf210213abb..a889601a4c166 100644 --- a/x-pack/plugins/infra/public/components/range_date_picker/index.tsx +++ b/x-pack/plugins/infra/public/components/range_date_picker/index.tsx @@ -255,6 +255,7 @@ export const RangeDatePicker = injectI18n( id="QuickSelectPopover" button={quickSelectButton} isOpen={this.state.isPopoverOpen} + // @ts-ignore closePopover={this.closePopover.bind(this)} anchorPosition="downLeft" ownFocus diff --git a/x-pack/plugins/infra/public/components/waffle/node.tsx b/x-pack/plugins/infra/public/components/waffle/node.tsx index 42d38a356a7fa..bf28453bda229 100644 --- a/x-pack/plugins/infra/public/components/waffle/node.tsx +++ b/x-pack/plugins/infra/public/components/waffle/node.tsx @@ -10,6 +10,7 @@ import { darken, readableColor } from 'polished'; import React from 'react'; import styled from 'styled-components'; +import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { InfraNodeType } from '../../../server/lib/adapters/nodes'; import { InfraTimerangeInput } from '../../graphql/types'; import { InfraWaffleMapBounds, InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib'; @@ -30,71 +31,90 @@ interface Props { bounds: InfraWaffleMapBounds; nodeType: InfraNodeType; timeRange: InfraTimerangeInput; + intl: InjectedIntl; } -export class Node extends React.PureComponent { - public readonly state: State = initialState; - public render() { - const { nodeType, node, options, squareSize, bounds, formatter, timeRange } = this.props; - const { isPopoverOpen } = this.state; - const { metric } = node; - const valueMode = squareSize > 70; - const ellipsisMode = squareSize > 30; - const rawValue = (metric && metric.value) || 0; - const color = colorFromValue(options.legend, rawValue, bounds); - const value = formatter(rawValue); - const newTimerange = { - ...timeRange, - from: moment(timeRange.to) - .subtract(1, 'hour') - .valueOf(), - }; - return ( - - - - - - {valueMode ? ( - - - {value} - - ) : ( - ellipsisMode && ( - - +export const Node = injectI18n( + class extends React.PureComponent { + public readonly state: State = initialState; + public render() { + const { + nodeType, + node, + options, + squareSize, + bounds, + formatter, + timeRange, + intl, + } = this.props; + const { isPopoverOpen } = this.state; + const { metric } = node; + const valueMode = squareSize > 70; + const ellipsisMode = squareSize > 30; + const rawValue = (metric && metric.value) || 0; + const color = colorFromValue(options.legend, rawValue, bounds); + const value = formatter(rawValue); + const newTimerange = { + ...timeRange, + from: moment(timeRange.to) + .subtract(1, 'hour') + .valueOf(), + }; + const nodeAriaLabel = intl.formatMessage( + { + id: 'xpack.infra.node.ariaLabel', + defaultMessage: '{nodeName}, click to open menu', + }, + { nodeName: node.name } + ); + return ( + + + + + + {valueMode ? ( + + + {value} - ) - )} - - - - - - ); - } + ) : ( + ellipsisMode && ( + + + + ) + )} + + + + + + ); + } - private togglePopover = () => { - this.setState(prevState => ({ isPopoverOpen: !prevState.isPopoverOpen })); - }; + private togglePopover = () => { + this.setState(prevState => ({ isPopoverOpen: !prevState.isPopoverOpen })); + }; - private closePopover = () => { - if (this.state.isPopoverOpen) { - this.setState({ isPopoverOpen: false }); - } - }; -} + private closePopover = () => { + if (this.state.isPopoverOpen) { + this.setState({ isPopoverOpen: false }); + } + }; + } +); const NodeContainer = styled.div` position: relative; @@ -126,7 +146,7 @@ const SquareInner = styled('div')` background-color: ${props => props.color}; `; -const ValueInner = styled.div` +const ValueInner = styled.button` position: absolute; top: 0; left: 0; @@ -139,6 +159,14 @@ const ValueInner = styled.div` padding: 1em; overflow: hidden; flex-wrap: wrap; + width: 100%; + border: none; + &:focus { + outline: none !important; + border: ${params => params.theme.eui.euiFocusRingSize} solid + ${params => params.theme.eui.euiFocusRingColor}; + box-shadow: none; + } `; const Value = styled('div')` diff --git a/x-pack/plugins/infra/public/containers/with_state_from_location.tsx b/x-pack/plugins/infra/public/containers/with_state_from_location.tsx index b8c8c85d96631..d11c9c3b0c511 100644 --- a/x-pack/plugins/infra/public/containers/with_state_from_location.tsx +++ b/x-pack/plugins/infra/public/containers/with_state_from_location.tsx @@ -50,6 +50,7 @@ export const withStateFromLocation = ({ const stateFromLocation = mapLocationToState(location); return ( + // @ts-ignore = WrappedActionCreator extends () export const bindPlainActionCreators = ( actionCreators: WrappedActionCreators ) => (dispatch: Dispatch) => - bindActionCreators(actionCreators, dispatch) as { + (bindActionCreators(actionCreators, dispatch) as unknown) as { [P in keyof WrappedActionCreators]: PlainActionCreator }; diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts index e605efc105617..b5f436994ddea 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts @@ -204,12 +204,12 @@ export interface LogEntryDocumentFields { const convertLogDocumentToEntry = ( sourceId: string, - formatMessage: (fields: LogEntryDocumentFields) => InfraLogMessageSegment[] + formatLogMessage: (fields: LogEntryDocumentFields) => InfraLogMessageSegment[] ) => (document: LogEntryDocument): InfraLogEntry => ({ key: document.key, gid: document.gid, source: sourceId, - message: formatMessage(document.fields), + message: formatLogMessage(document.fields), }); const convertDateRangeBucketToSummaryBucket = ( diff --git a/x-pack/plugins/license_management/__jest__/__snapshots__/request_trial_extension.test.js.snap b/x-pack/plugins/license_management/__jest__/__snapshots__/request_trial_extension.test.js.snap index ae37f4357b578..5b7d5126e501f 100644 --- a/x-pack/plugins/license_management/__jest__/__snapshots__/request_trial_extension.test.js.snap +++ b/x-pack/plugins/license_management/__jest__/__snapshots__/request_trial_extension.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`RequestTrialExtension component should display when license is active and trial has been used 1`] = `"
Extend your trial

If you’d like to continuing using security, machine learning, and our other awesome Platinum features, request an extension now.

Extend trial
"`; +exports[`RequestTrialExtension component should display when license is active and trial has been used 1`] = `"
Extend your trial

If you’d like to continuing using security, machine learning, and our other awesome Platinum features, request an extension now.

Extend trial
"`; -exports[`RequestTrialExtension component should display when license is not active and trial has been used 1`] = `"
Extend your trial

If you’d like to continuing using security, machine learning, and our other awesome Platinum features, request an extension now.

Extend trial
"`; +exports[`RequestTrialExtension component should display when license is not active and trial has been used 1`] = `"
Extend your trial

If you’d like to continuing using security, machine learning, and our other awesome Platinum features, request an extension now.

Extend trial
"`; -exports[`RequestTrialExtension component should display when platinum license is not active and trial has been used 1`] = `"
Extend your trial

If you’d like to continuing using security, machine learning, and our other awesome Platinum features, request an extension now.

Extend trial
"`; +exports[`RequestTrialExtension component should display when platinum license is not active and trial has been used 1`] = `"
Extend your trial

If you’d like to continuing using security, machine learning, and our other awesome Platinum features, request an extension now.

Extend trial
"`; diff --git a/x-pack/plugins/license_management/__jest__/__snapshots__/revert_to_basic.test.js.snap b/x-pack/plugins/license_management/__jest__/__snapshots__/revert_to_basic.test.js.snap index 290c43ba514ab..eab0dada04de0 100644 --- a/x-pack/plugins/license_management/__jest__/__snapshots__/revert_to_basic.test.js.snap +++ b/x-pack/plugins/license_management/__jest__/__snapshots__/revert_to_basic.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`RevertToBasic component should display when license is about to expire 1`] = `"
Revert to Basic license

You’ll revert to our free features and lose access to security, machine learning and other Platinum features.

"`; +exports[`RevertToBasic component should display when license is about to expire 1`] = `"
Revert to Basic license

You’ll revert to our free features and lose access to security, machine learning and other Platinum features.

"`; -exports[`RevertToBasic component should display when license is expired 1`] = `"
Revert to Basic license

You’ll revert to our free features and lose access to security, machine learning and other Platinum features.

"`; +exports[`RevertToBasic component should display when license is expired 1`] = `"
Revert to Basic license

You’ll revert to our free features and lose access to security, machine learning and other Platinum features.

"`; -exports[`RevertToBasic component should display when trial is active 1`] = `"
Revert to Basic license

You’ll revert to our free features and lose access to security, machine learning and other Platinum features.

"`; +exports[`RevertToBasic component should display when trial is active 1`] = `"
Revert to Basic license

You’ll revert to our free features and lose access to security, machine learning and other Platinum features.

"`; diff --git a/x-pack/plugins/license_management/__jest__/__snapshots__/start_trial.test.js.snap b/x-pack/plugins/license_management/__jest__/__snapshots__/start_trial.test.js.snap index 277033f3ee111..ab78cc599cd40 100644 --- a/x-pack/plugins/license_management/__jest__/__snapshots__/start_trial.test.js.snap +++ b/x-pack/plugins/license_management/__jest__/__snapshots__/start_trial.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`StartTrial component when trial is allowed display for basic license 1`] = `"
Start a 30-day trial

Experience what security, machine learning, and all our other Platinum features have to offer.

"`; +exports[`StartTrial component when trial is allowed display for basic license 1`] = `"
Start a 30-day trial

Experience what security, machine learning, and all our other Platinum features have to offer.

"`; -exports[`StartTrial component when trial is allowed should display for expired platinum license 1`] = `"
Start a 30-day trial

Experience what security, machine learning, and all our other Platinum features have to offer.

"`; +exports[`StartTrial component when trial is allowed should display for expired platinum license 1`] = `"
Start a 30-day trial

Experience what security, machine learning, and all our other Platinum features have to offer.

"`; -exports[`StartTrial component when trial is allowed should display for gold license 1`] = `"
Start a 30-day trial

Experience what security, machine learning, and all our other Platinum features have to offer.

"`; +exports[`StartTrial component when trial is allowed should display for gold license 1`] = `"
Start a 30-day trial

Experience what security, machine learning, and all our other Platinum features have to offer.

"`; diff --git a/x-pack/plugins/license_management/__jest__/api_responses/index.js b/x-pack/plugins/license_management/__jest__/api_responses/index.js index b4d08a97cf3e8..33132a9623d47 100644 --- a/x-pack/plugins/license_management/__jest__/api_responses/index.js +++ b/x-pack/plugins/license_management/__jest__/api_responses/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './upload_license'; \ No newline at end of file +export * from './upload_license'; diff --git a/x-pack/plugins/license_management/__jest__/telemetry_opt_in.test.js b/x-pack/plugins/license_management/__jest__/telemetry_opt_in.test.js index 3ed9a11d6d9b7..3b0eee38e3c9e 100644 --- a/x-pack/plugins/license_management/__jest__/telemetry_opt_in.test.js +++ b/x-pack/plugins/license_management/__jest__/telemetry_opt_in.test.js @@ -20,4 +20,4 @@ describe('TelemetryOptIn', () => { const rendered = mountWithIntl(); expect(rendered).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/license_management/__jest__/util/index.js b/x-pack/plugins/license_management/__jest__/util/index.js index abba94291d529..e771c1f1ee8ad 100644 --- a/x-pack/plugins/license_management/__jest__/util/index.js +++ b/x-pack/plugins/license_management/__jest__/util/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './util'; \ No newline at end of file +export * from './util'; diff --git a/x-pack/plugins/license_management/common/constants/external_links.js b/x-pack/plugins/license_management/common/constants/external_links.js new file mode 100644 index 0000000000000..66442aaee8d4a --- /dev/null +++ b/x-pack/plugins/license_management/common/constants/external_links.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +const ELASTIC_BASE_URL = 'https://www.elastic.co/'; + +export const EXTERNAL_LINKS = { + SUBSCRIPTIONS: `${ELASTIC_BASE_URL}subscriptions`, + TRIAL_EXTENSION: `${ELASTIC_BASE_URL}trialextension`, + TRIAL_LICENSE: `${ELASTIC_BASE_URL}legal/trial_license` +}; diff --git a/x-pack/plugins/license_management/common/constants/index.js b/x-pack/plugins/license_management/common/constants/index.js index 59b61f7b99f98..58b6a9ab6992f 100644 --- a/x-pack/plugins/license_management/common/constants/index.js +++ b/x-pack/plugins/license_management/common/constants/index.js @@ -6,3 +6,4 @@ export { PLUGIN } from './plugin'; export { BASE_PATH } from './base_path'; +export { EXTERNAL_LINKS } from './external_links'; diff --git a/x-pack/plugins/license_management/common/constants/plugin.js b/x-pack/plugins/license_management/common/constants/plugin.js index dd1301c33f979..7da3dbdeba1c8 100644 --- a/x-pack/plugins/license_management/common/constants/plugin.js +++ b/x-pack/plugins/license_management/common/constants/plugin.js @@ -4,6 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; + export const PLUGIN = { - ID: 'license_management' + ID: 'license_management', + NAME: i18n.translate('xpack.licenseMgmt.managementSectionDisplayName', { + defaultMessage: 'License Management', + }), + MINIMUM_LICENSE_REQUIRED: 'basic', }; diff --git a/x-pack/plugins/license_management/index.js b/x-pack/plugins/license_management/index.js index 077a908ace429..b515f326dbf5c 100644 --- a/x-pack/plugins/license_management/index.js +++ b/x-pack/plugins/license_management/index.js @@ -23,9 +23,9 @@ export function licenseManagement(kibana) { ] }, init: (server) => { - registerLicenseChecker(server, PLUGIN.ID); const xpackInfo = server.plugins.xpack_main.info; const router = createRouter(server, PLUGIN.ID, '/api/license'); + registerLicenseChecker(server, PLUGIN.ID, PLUGIN.NAME, PLUGIN.MINIMUM_LICENSE_REQUIRED); registerLicenseRoute(router, xpackInfo); registerStartTrialRoutes(router, xpackInfo); registerStartBasicRoute(router, xpackInfo); diff --git a/x-pack/plugins/license_management/public/app.js b/x-pack/plugins/license_management/public/app.js index f65274ff13f32..28f68aa05bc2c 100644 --- a/x-pack/plugins/license_management/public/app.js +++ b/x-pack/plugins/license_management/public/app.js @@ -17,4 +17,4 @@ export default () => ( -); \ No newline at end of file +); diff --git a/x-pack/plugins/license_management/public/components/telemetry_opt_in/index.js b/x-pack/plugins/license_management/public/components/telemetry_opt_in/index.js index 4bef20b8b4a08..7d9e35cf20081 100644 --- a/x-pack/plugins/license_management/public/components/telemetry_opt_in/index.js +++ b/x-pack/plugins/license_management/public/components/telemetry_opt_in/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { TelemetryOptIn } from './telemetry_opt_in'; \ No newline at end of file +export { TelemetryOptIn } from './telemetry_opt_in'; diff --git a/x-pack/plugins/license_management/public/index.js b/x-pack/plugins/license_management/public/index.js index 79d4f1c431cb5..0e7c3ae60c775 100644 --- a/x-pack/plugins/license_management/public/index.js +++ b/x-pack/plugins/license_management/public/index.js @@ -5,4 +5,4 @@ */ import './management_section'; -import './register_route'; \ No newline at end of file +import './register_route'; diff --git a/x-pack/plugins/license_management/public/sections/license_dashboard/request_trial_extension/request_trial_extension.js b/x-pack/plugins/license_management/public/sections/license_dashboard/request_trial_extension/request_trial_extension.js index 74bd38aa41757..baeab9c899dac 100644 --- a/x-pack/plugins/license_management/public/sections/license_dashboard/request_trial_extension/request_trial_extension.js +++ b/x-pack/plugins/license_management/public/sections/license_dashboard/request_trial_extension/request_trial_extension.js @@ -8,6 +8,7 @@ import React from 'react'; import { EuiFlexItem, EuiCard, EuiLink, EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { EXTERNAL_LINKS } from '../../../../common/constants'; export const RequestTrialExtension = ({ shouldShowRequestTrialExtension }) => { if (!shouldShowRequestTrialExtension) { @@ -22,7 +23,7 @@ export const RequestTrialExtension = ({ shouldShowRequestTrialExtension }) => { values={{ platinumLicenseFeaturesLinkText: ( { { @@ -81,7 +82,7 @@ export class RevertToBasic extends React.PureComponent { values={{ platinumLicenseFeaturesLinkText: ( { - const pipeline = server.config().get('elasticsearch'); - const cluster = server.plugins.elasticsearch.createCluster('logstash', pipeline); + const cluster = server.plugins.elasticsearch.createCluster('logstash'); return cluster.callWithRequest; }); diff --git a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js index 16139b000e61c..582c021892d42 100755 --- a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js +++ b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js @@ -88,4 +88,4 @@ describe('fetch_all_from_scroll', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/logstash/server/routes/api/pipeline/register_delete_route.js b/x-pack/plugins/logstash/server/routes/api/pipeline/register_delete_route.js index 9702e35ac5152..9384f302f7a4f 100755 --- a/x-pack/plugins/logstash/server/routes/api/pipeline/register_delete_route.js +++ b/x-pack/plugins/logstash/server/routes/api/pipeline/register_delete_route.js @@ -6,13 +6,12 @@ import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; import { wrapEsError } from '../../../lib/error_wrappers'; -import { INDEX_NAMES, TYPE_NAMES } from '../../../../common/constants'; +import { INDEX_NAMES } from '../../../../common/constants'; import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory'; function deletePipeline(callWithRequest, pipelineId) { return callWithRequest('delete', { index: INDEX_NAMES.PIPELINES, - type: TYPE_NAMES.PIPELINES, id: pipelineId, refresh: 'wait_for' }); diff --git a/x-pack/plugins/logstash/server/routes/api/pipeline/register_load_route.js b/x-pack/plugins/logstash/server/routes/api/pipeline/register_load_route.js index 90e897a18eb86..ef63cf4cb2d7f 100755 --- a/x-pack/plugins/logstash/server/routes/api/pipeline/register_load_route.js +++ b/x-pack/plugins/logstash/server/routes/api/pipeline/register_load_route.js @@ -5,7 +5,7 @@ */ import Boom from 'boom'; -import { INDEX_NAMES, TYPE_NAMES } from '../../../../common/constants'; +import { INDEX_NAMES } from '../../../../common/constants'; import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; import { Pipeline } from '../../../models/pipeline'; import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory'; @@ -13,7 +13,6 @@ import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factor function fetchPipeline(callWithRequest, pipelineId) { return callWithRequest('get', { index: INDEX_NAMES.PIPELINES, - type: TYPE_NAMES.PIPELINES, id: pipelineId, _source: [ 'description', diff --git a/x-pack/plugins/logstash/server/routes/api/pipeline/register_save_route.js b/x-pack/plugins/logstash/server/routes/api/pipeline/register_save_route.js index 235392e42620b..102b1b6da05b2 100755 --- a/x-pack/plugins/logstash/server/routes/api/pipeline/register_save_route.js +++ b/x-pack/plugins/logstash/server/routes/api/pipeline/register_save_route.js @@ -6,7 +6,7 @@ import { get } from 'lodash'; import { wrapEsError } from '../../../lib/error_wrappers'; -import { INDEX_NAMES, TYPE_NAMES } from '../../../../common/constants'; +import { INDEX_NAMES } from '../../../../common/constants'; import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; import { Pipeline } from '../../../models/pipeline'; import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory'; @@ -14,7 +14,6 @@ import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factor function savePipeline(callWithRequest, pipelineId, pipelineBody) { return callWithRequest('index', { index: INDEX_NAMES.PIPELINES, - type: TYPE_NAMES.PIPELINES, id: pipelineId, body: pipelineBody, refresh: 'wait_for' diff --git a/x-pack/plugins/logstash/server/routes/api/pipelines/index.js b/x-pack/plugins/logstash/server/routes/api/pipelines/index.js index 25ef2b8d805a2..db275b5a3ea79 100755 --- a/x-pack/plugins/logstash/server/routes/api/pipelines/index.js +++ b/x-pack/plugins/logstash/server/routes/api/pipelines/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { registerLogstashPipelinesRoutes } from './register_pipelines_routes'; \ No newline at end of file +export { registerLogstashPipelinesRoutes } from './register_pipelines_routes'; diff --git a/x-pack/plugins/logstash/server/routes/api/pipelines/register_delete_route.js b/x-pack/plugins/logstash/server/routes/api/pipelines/register_delete_route.js index faed6d2149eb3..1ddbf227ffb37 100755 --- a/x-pack/plugins/logstash/server/routes/api/pipelines/register_delete_route.js +++ b/x-pack/plugins/logstash/server/routes/api/pipelines/register_delete_route.js @@ -6,14 +6,13 @@ import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; import { wrapUnknownError } from '../../../lib/error_wrappers'; -import { INDEX_NAMES, TYPE_NAMES } from '../../../../common/constants'; +import { INDEX_NAMES } from '../../../../common/constants'; import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory'; function deletePipelines(callWithRequest, pipelineIds) { const deletePromises = pipelineIds.map(pipelineId => { return callWithRequest('delete', { index: INDEX_NAMES.PIPELINES, - type: TYPE_NAMES.PIPELINES, id: pipelineId, refresh: 'wait_for' }) diff --git a/x-pack/plugins/logstash/server/routes/api/upgrade/register_execute_route.js b/x-pack/plugins/logstash/server/routes/api/upgrade/register_execute_route.js index aa0517e089b5a..c86adc612076a 100755 --- a/x-pack/plugins/logstash/server/routes/api/upgrade/register_execute_route.js +++ b/x-pack/plugins/logstash/server/routes/api/upgrade/register_execute_route.js @@ -6,7 +6,7 @@ import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; import { wrapUnknownError } from '../../../lib/error_wrappers'; -import { INDEX_NAMES, TYPE_NAMES } from '../../../../common/constants'; +import { INDEX_NAMES } from '../../../../common/constants'; import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory'; function doesIndexExist(callWithRequest) { @@ -24,8 +24,6 @@ async function executeUpgrade(callWithRequest) { return callWithRequest('indices.putMapping', { index: INDEX_NAMES.PIPELINES, - include_type_name: true, - type: TYPE_NAMES.PIPELINES, body: { properties: { pipeline_settings: { diff --git a/x-pack/plugins/maps/index.js b/x-pack/plugins/maps/index.js index c604f2b4d7fbb..ba6a4fcfd4b45 100644 --- a/x-pack/plugins/maps/index.js +++ b/x-pack/plugins/maps/index.js @@ -39,6 +39,9 @@ export function maps(kibana) { isEmsEnabled: mapConfig.includeElasticMapsService, }; }, + embeddableFactories: [ + 'plugins/maps/embeddable/map_embeddable_factory_provider' + ], inspectorViews: [ 'plugins/maps/inspector/views/register_views', ], diff --git a/x-pack/plugins/maps/public/actions/store_actions.js b/x-pack/plugins/maps/public/actions/store_actions.js index af1a61c313f5e..a895655d1e2c8 100644 --- a/x-pack/plugins/maps/public/actions/store_actions.js +++ b/x-pack/plugins/maps/public/actions/store_actions.js @@ -479,7 +479,7 @@ export function removeLayer(id) { }; } -export function setQuery({ query, timeFilters }) { +export function setQuery({ query, timeFilters, filters = [] }) { return async (dispatch, getState) => { dispatch({ type: SET_QUERY, @@ -489,6 +489,7 @@ export function setQuery({ query, timeFilters }) { // ensure query changes to trigger re-fetch even when query is the same because "Refresh" clicked queryLastTriggeredAt: (new Date()).toISOString(), }, + filters, }); const dataFilters = getDataFilters(getState()); diff --git a/x-pack/plugins/maps/public/angular/services/gis_map_saved_object_loader.js b/x-pack/plugins/maps/public/angular/services/gis_map_saved_object_loader.js index 07e721bb09675..88f25505568c1 100644 --- a/x-pack/plugins/maps/public/angular/services/gis_map_saved_object_loader.js +++ b/x-pack/plugins/maps/public/angular/services/gis_map_saved_object_loader.js @@ -7,17 +7,9 @@ import './saved_gis_map'; import { uiModules } from 'ui/modules'; import { SavedObjectLoader, SavedObjectsClientProvider } from 'ui/saved_objects'; -import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry'; const module = uiModules.get('app/maps'); -// Register this service with the saved object registry so it can be -// edited by the object editor. -SavedObjectRegistryProvider.register({ - service: 'gisMapSavedObjectLoader', - title: 'gisMaps' -}); - // This is the only thing that gets injected into controllers module.service('gisMapSavedObjectLoader', function (Private, SavedGisMap, kbnIndex, kbnUrl, $http, chrome) { const savedObjectClient = Private(SavedObjectsClientProvider); diff --git a/x-pack/plugins/maps/public/angular/services/saved_gis_map.js b/x-pack/plugins/maps/public/angular/services/saved_gis_map.js index 58b83e47661ad..3e08bb5cedf73 100644 --- a/x-pack/plugins/maps/public/angular/services/saved_gis_map.js +++ b/x-pack/plugins/maps/public/angular/services/saved_gis_map.js @@ -39,6 +39,15 @@ module.factory('SavedGisMap', function (Private) { }); savedObject.layerListJSON = attributes.layerListJSON; + + const indexPatternIds = references + .filter(reference => { + return reference.type === 'index-pattern'; + }) + .map(reference => { + return reference.id; + }); + savedObject.indexPatternIds = _.uniq(indexPatternIds); }, // if this is null/undefined then the SavedObject will be assigned the defaults diff --git a/x-pack/plugins/maps/public/components/layer_panel/style_tabs/resources/style_tab.js b/x-pack/plugins/maps/public/components/layer_panel/style_tabs/resources/style_tab.js index 4132692414c1a..6a503ddaae75c 100644 --- a/x-pack/plugins/maps/public/components/layer_panel/style_tabs/resources/style_tab.js +++ b/x-pack/plugins/maps/public/components/layer_panel/style_tabs/resources/style_tab.js @@ -25,4 +25,4 @@ export function StyleTab(props) { >{ name } ) || null; -} \ No newline at end of file +} diff --git a/x-pack/plugins/maps/public/components/map/mb/view.js b/x-pack/plugins/maps/public/components/map/mb/view.js index 5a7e15df3ced7..0729557dc86f6 100644 --- a/x-pack/plugins/maps/public/components/map/mb/view.js +++ b/x-pack/plugins/maps/public/components/map/mb/view.js @@ -93,8 +93,7 @@ export class MBMapContainer extends React.Component { originalMbBoxRemoveLayerFunc.apply(this._mbMap, [id]); }; - this.assignSizeWatch(); - + this._initResizerChecker(); // moveend callback is debounced to avoid updating map extent state while map extent is still changing // moveend is fired while the map extent is still changing in the following scenarios @@ -149,20 +148,11 @@ export class MBMapContainer extends React.Component { } } - assignSizeWatch() { + _initResizerChecker() { this._checker = new ResizeChecker(this.refs.mapContainer); - this._checker.on('resize', (() => { - let lastWidth = window.innerWidth; - let lastHeight = window.innerHeight; - return () => { - if (lastWidth === window.innerWidth - && lastHeight === window.innerHeight && this._mbMap) { - this._mbMap.resize(); - } - lastWidth = window.innerWidth; - lastHeight = window.innerHeight; - }; - })()); + this._checker.on('resize', () => { + this._mbMap.resize(); + }); } _syncMbMapWithMapState = () => { diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.js b/x-pack/plugins/maps/public/embeddable/map_embeddable.js new file mode 100644 index 0000000000000..c26f7dda5a648 --- /dev/null +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.js @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import _ from 'lodash'; +import React from 'react'; +import { Provider } from 'react-redux'; +import { render, unmountComponentAtNode } from 'react-dom'; +import 'mapbox-gl/dist/mapbox-gl.css'; + +import { Embeddable } from 'ui/embeddable'; +import { I18nContext } from 'ui/i18n'; + +import { GisMap } from '../components/gis_map'; +import { createMapStore } from '../store/store'; +import { getInitialLayers } from '../angular/get_initial_layers'; +import { + setGotoWithCenter, + replaceLayerList, + setQuery, + setRefreshConfig, +} from '../actions/store_actions'; +import { setReadOnly } from '../store/ui'; +import { getInspectorAdapters } from '../store/non_serializable_instances'; + +export class MapEmbeddable extends Embeddable { + + constructor({ savedMap, editUrl, indexPatterns = [] }) { + super({ title: savedMap.title, editUrl, indexPatterns }); + + this._savedMap = savedMap; + this._store = createMapStore(); + } + + getInspectorAdapters() { + return getInspectorAdapters(this._store.getState()); + } + + onContainerStateChanged(containerState) { + if (!_.isEqual(containerState.timeRange, this._prevTimeRange) || + !_.isEqual(containerState.query, this._prevQuery) || + !_.isEqual(containerState.filters, this._prevFilters)) { + this._dispatchSetQuery(containerState); + } + + if (!_.isEqual(containerState.refreshConfig, this._prevRefreshConfig)) { + this._dispatchSetRefreshConfig(containerState); + } + } + + _dispatchSetQuery({ query, timeRange, filters }) { + this._prevTimeRange = timeRange; + this._prevQuery = query; + this._prevFilters = filters; + this._store.dispatch(setQuery({ + filters: filters.filter(filter => !filter.meta.disabled), + query, + timeFilters: timeRange, + })); + } + + _dispatchSetRefreshConfig({ refreshConfig }) { + this._prevRefreshConfig = refreshConfig; + this._store.dispatch(setRefreshConfig(refreshConfig)); + } + + /** + * + * @param {HTMLElement} domNode + * @param {ContainerState} containerState + */ + render(domNode, containerState) { + this._store.dispatch(setReadOnly(true)); + // todo get center and zoom from embeddable UI state + if (this._savedMap.mapStateJSON) { + const mapState = JSON.parse(this._savedMap.mapStateJSON); + this._store.dispatch(setGotoWithCenter({ + lat: mapState.center.lat, + lon: mapState.center.lon, + zoom: mapState.zoom, + })); + } + const layerList = getInitialLayers(this._savedMap.layerListJSON); + this._store.dispatch(replaceLayerList(layerList)); + this._dispatchSetQuery(containerState); + this._dispatchSetRefreshConfig(containerState); + + render( + + + + + , + domNode + ); + } + + destroy() { + this._savedMap.destroy(); + if (this._domNode) { + unmountComponentAtNode(this._domNode); + } + } + + reload() { + this._dispatchSetQuery({ + query: this._prevQuery, + timeRange: this._prevTimeRange, + filters: this._prevFilters + }); + } +} diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.js b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.js new file mode 100644 index 0000000000000..b280584db65a2 --- /dev/null +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.js @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import _ from 'lodash'; +import chrome from 'ui/chrome'; +import { EmbeddableFactory } from 'ui/embeddable'; +import { MapEmbeddable } from './map_embeddable'; +import { indexPatternService } from '../kibana_services'; + +export class MapEmbeddableFactory extends EmbeddableFactory { + + constructor(gisMapSavedObjectLoader) { + super({ name: 'map' }); + this._savedObjectLoader = gisMapSavedObjectLoader; + } + + async _getIndexPatterns(indexPatternIds = []) { + const promises = indexPatternIds.map(async (indexPatternId) => { + try { + return await indexPatternService.get(indexPatternId); + } catch (error) { + // Unable to load index pattern, better to not throw error so map embeddable can render + // Error will be surfaced by map embeddable since it too will be unable to locate the index pattern + return null; + } + }); + const indexPatterns = await Promise.all(promises); + return _.compact(indexPatterns); + } + + async create(panelMetadata, onEmbeddableStateChanged) { + const savedMap = await this._savedObjectLoader.get(panelMetadata.id); + const indexPatterns = await this._getIndexPatterns(savedMap.indexPatternIds); + + return new MapEmbeddable({ + onEmbeddableStateChanged, + savedMap, + editUrl: chrome.addBasePath(`/app/maps#/map/${panelMetadata.id}`), + indexPatterns, + }); + } +} diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory_provider.js b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory_provider.js new file mode 100644 index 0000000000000..38be62a658f0f --- /dev/null +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory_provider.js @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EmbeddableFactoriesRegistryProvider } from 'ui/embeddable/embeddable_factories_registry'; +import { MapEmbeddableFactory } from './map_embeddable_factory'; +import '../angular/services/gis_map_saved_object_loader'; + +function mapEmbeddableFactoryProvider(gisMapSavedObjectLoader) { + return new MapEmbeddableFactory(gisMapSavedObjectLoader); +} + +EmbeddableFactoriesRegistryProvider.register(mapEmbeddableFactoryProvider); diff --git a/x-pack/plugins/maps/public/index.js b/x-pack/plugins/maps/public/index.js index 89b095e2fbd47..c8de69bc6c8d5 100644 --- a/x-pack/plugins/maps/public/index.js +++ b/x-pack/plugins/maps/public/index.js @@ -14,6 +14,7 @@ import 'uiExports/autocompleteProviders'; import 'uiExports/fieldFormats'; import 'uiExports/inspectorViews'; import 'uiExports/search'; +import 'uiExports/embeddableFactories'; import 'ui/agg_types'; import chrome from 'ui/chrome'; @@ -101,4 +102,4 @@ routes }) .otherwise({ redirectTo: '/' - }); \ No newline at end of file + }); diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.js b/x-pack/plugins/maps/public/selectors/map_selectors.js index a5e40d52dfe08..55c6f7c4d649c 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.js +++ b/x-pack/plugins/maps/public/selectors/map_selectors.js @@ -105,7 +105,19 @@ export const getTimeFilters = ({ map }) => map.mapState.timeFilters ? export const getQuery = ({ map }) => map.mapState.query; -export const getRefreshConfig = ({ map }) => map.mapState.refreshConfig; +export const getFilters = ({ map }) => map.mapState.filters; + +export const getRefreshConfig = ({ map }) => { + if (map.mapState.refreshConfig) { + return map.mapState.refreshConfig; + } + + const refreshInterval = timefilter.getRefreshInterval(); + return { + isPaused: refreshInterval.pause, + interval: refreshInterval.value, + }; +}; export const getRefreshTimerLastTriggeredAt = ({ map }) => map.mapState.refreshTimerLastTriggeredAt; @@ -116,7 +128,8 @@ export const getDataFilters = createSelector( getTimeFilters, getRefreshTimerLastTriggeredAt, getQuery, - (mapExtent, mapBuffer, mapZoom, timeFilters, refreshTimerLastTriggeredAt, query) => { + getFilters, + (mapExtent, mapBuffer, mapZoom, timeFilters, refreshTimerLastTriggeredAt, query, filters) => { return { extent: mapExtent, buffer: mapBuffer, @@ -124,6 +137,7 @@ export const getDataFilters = createSelector( timeFilters, refreshTimerLastTriggeredAt, query, + filters, }; } ); diff --git a/x-pack/plugins/maps/public/shared/layers/heatmap_layer.js b/x-pack/plugins/maps/public/shared/layers/heatmap_layer.js index 9207f8f298a5d..7ce0ea9ce39ef 100644 --- a/x-pack/plugins/maps/public/shared/layers/heatmap_layer.js +++ b/x-pack/plugins/maps/public/shared/layers/heatmap_layer.js @@ -112,54 +112,52 @@ export class HeatmapLayer extends AbstractLayer { } const sourceDataRequest = this.getSourceDataRequest(); - const dataMeta = sourceDataRequest ? sourceDataRequest.getMeta() : {}; + const meta = sourceDataRequest ? sourceDataRequest.getMeta() : {}; const geogridPrecision = this._source.getGeoGridPrecision(dataFilters.zoom); - const isSamePrecision = dataMeta.geogridPrecision === geogridPrecision; + const isSamePrecision = meta.geogridPrecision === geogridPrecision; - const isSameTime = _.isEqual(dataMeta.timeFilters, dataFilters.timeFilters); + const isSameTime = _.isEqual(meta.timeFilters, dataFilters.timeFilters); const updateDueToRefreshTimer = dataFilters.refreshTimerLastTriggeredAt - && !_.isEqual(dataMeta.refreshTimerLastTriggeredAt, dataFilters.refreshTimerLastTriggeredAt); + && !_.isEqual(meta.refreshTimerLastTriggeredAt, dataFilters.refreshTimerLastTriggeredAt); - const updateDueToExtent = this.updateDueToExtent(this._source, dataMeta, dataFilters); + const updateDueToExtent = this.updateDueToExtent(this._source, meta, dataFilters); const updateDueToQuery = dataFilters.query - && !_.isEqual(dataMeta.query, dataFilters.query); + && !_.isEqual(meta.query, dataFilters.query); + + const updateDueToFilters = dataFilters.filters + && !_.isEqual(meta.filters, dataFilters.filters); const metricPropertyKey = this._getPropKeyOfSelectedMetric(); - const updateDueToMetricChange = !_.isEqual(dataMeta.metric, metricPropertyKey); + const updateDueToMetricChange = !_.isEqual(meta.metric, metricPropertyKey); if (isSamePrecision && isSameTime && !updateDueToExtent && !updateDueToRefreshTimer && !updateDueToQuery + && !updateDueToFilters && !updateDueToMetricChange ) { return; } - const newDataMeta = { + const searchFilters = { ...dataFilters, geogridPrecision, metric: metricPropertyKey }; - await this._fetchNewData({ startLoading, stopLoading, onLoadError, dataMeta: newDataMeta }); + await this._fetchNewData({ startLoading, stopLoading, onLoadError, searchFilters }); } - async _fetchNewData({ startLoading, stopLoading, onLoadError, dataMeta }) { - const { geogridPrecision, timeFilters, buffer, query } = dataMeta; + async _fetchNewData({ startLoading, stopLoading, onLoadError, searchFilters }) { const requestToken = Symbol(`layer-source-refresh: this.getId()`); - startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, dataMeta); + startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, searchFilters); try { const layerName = await this.getDisplayName(); - const data = await this._source.getGeoJsonPoints({ layerName }, { - geogridPrecision, - buffer, - timeFilters, - query, - }); + const data = await this._source.getGeoJsonPoints(layerName, searchFilters); stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, data); } catch (error) { onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message); diff --git a/x-pack/plugins/maps/public/shared/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/plugins/maps/public/shared/layers/sources/es_geo_grid_source/es_geo_grid_source.js index 9a23a52411fb1..3ce3167edd2b0 100644 --- a/x-pack/plugins/maps/public/shared/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/plugins/maps/public/shared/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -148,14 +148,9 @@ export class ESGeoGridSource extends AbstractESSource { throw new Error(`Grid resolution param not recognized: ${this._descriptor.resolution}`); } - async getGeoJsonWithMeta({ layerName }, searchFilters) { + async getGeoJsonWithMeta(layerName, searchFilters) { - const featureCollection = await this.getGeoJsonPoints({ layerName }, { - geogridPrecision: searchFilters.geogridPrecision, - buffer: searchFilters.buffer, - timeFilters: searchFilters.timeFilters, - query: searchFilters.query, - }); + const featureCollection = await this.getGeoJsonPoints(layerName, searchFilters); return { data: featureCollection, @@ -171,11 +166,11 @@ export class ESGeoGridSource extends AbstractESSource { }); } - async getGeoJsonPoints({ layerName }, { geogridPrecision, buffer, timeFilters, query }) { + async getGeoJsonPoints(layerName, searchFilters) { const indexPattern = await this._getIndexPattern(); - const searchSource = await this._makeSearchSource({ buffer, timeFilters, query }, 0); - const aggConfigs = new AggConfigs(indexPattern, this._makeAggConfigs(geogridPrecision), aggSchemas.all); + const searchSource = await this._makeSearchSource(searchFilters, 0); + const aggConfigs = new AggConfigs(indexPattern, this._makeAggConfigs(searchFilters.geogridPrecision), aggSchemas.all); searchSource.setField('aggs', aggConfigs.toDsl()); const esResponse = await this._runEsQuery(layerName, searchSource, 'Elasticsearch geohash_grid aggregation request'); diff --git a/x-pack/plugins/maps/public/shared/layers/sources/es_search_source/es_search_source.js b/x-pack/plugins/maps/public/shared/layers/sources/es_search_source/es_search_source.js index 8d76230ee25a7..c8b9b74a49a2c 100644 --- a/x-pack/plugins/maps/public/shared/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/plugins/maps/public/shared/layers/sources/es_search_source/es_search_source.js @@ -103,7 +103,7 @@ export class ESSearchSource extends AbstractESSource { ]; } - async getGeoJsonWithMeta({ layerName }, searchFilters) { + async getGeoJsonWithMeta(layerName, searchFilters) { const searchSource = await this._makeSearchSource(searchFilters, this._descriptor.limit); // Setting "fields" instead of "source: { includes: []}" // because SearchSource automatically adds the following by default diff --git a/x-pack/plugins/maps/public/shared/layers/sources/es_source.js b/x-pack/plugins/maps/public/shared/layers/sources/es_source.js index b9ad8d222feec..d31d668341d15 100644 --- a/x-pack/plugins/maps/public/shared/layers/sources/es_source.js +++ b/x-pack/plugins/maps/public/shared/layers/sources/es_source.js @@ -91,7 +91,7 @@ export class AbstractESSource extends AbstractVectorSource { } } - async _makeSearchSource({ buffer, query, timeFilters }, limit) { + async _makeSearchSource({ buffer, query, timeFilters, filters }, limit) { const indexPattern = await this._getIndexPattern(); const geoField = await this._getGeoField(); const isTimeAware = await this.isTimeAware(); @@ -99,22 +99,22 @@ export class AbstractESSource extends AbstractVectorSource { searchSource.setField('index', indexPattern); searchSource.setField('size', limit); searchSource.setField('filter', () => { - const filters = []; + const allFilters = [...filters]; if (this.isFilterByMapBounds() && buffer) {//buffer can be empty - filters.push(createExtentFilter(buffer, geoField.name, geoField.type)); + allFilters.push(createExtentFilter(buffer, geoField.name, geoField.type)); } if (isTimeAware) { - filters.push(timefilter.createFilter(indexPattern, timeFilters)); + allFilters.push(timefilter.createFilter(indexPattern, timeFilters)); } - return filters; + return allFilters; }); searchSource.setField('query', query); return searchSource; } - async getBoundsForFilters({ query, timeFilters }) { + async getBoundsForFilters({ query, timeFilters, filters }) { - const searchSource = await this._makeSearchSource({ query, timeFilters }, 0); + const searchSource = await this._makeSearchSource({ query, timeFilters, filters }, 0); const geoField = await this._getGeoField(); const indexPattern = await this._getIndexPattern(); diff --git a/x-pack/plugins/maps/public/shared/layers/vector_layer.js b/x-pack/plugins/maps/public/shared/layers/vector_layer.js index 3f26d4827b48d..bdd4368214206 100644 --- a/x-pack/plugins/maps/public/shared/layers/vector_layer.js +++ b/x-pack/plugins/maps/public/shared/layers/vector_layer.js @@ -202,8 +202,10 @@ export class VectorLayer extends AbstractLayer { } let updateDueToQuery = false; + let updateDueToFilters = false; if (isQueryAware) { updateDueToQuery = !_.isEqual(meta.query, searchFilters.query); + updateDueToFilters = !_.isEqual(meta.filters, searchFilters.filters); } let updateDueToPrecisionChange = false; @@ -218,6 +220,7 @@ export class VectorLayer extends AbstractLayer { && !updateDueToExtentChange && !updateDueToFields && !updateDueToQuery + && !updateDueToFilters && !updateDueToPrecisionChange; } @@ -297,9 +300,7 @@ export class VectorLayer extends AbstractLayer { try { startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, searchFilters); const layerName = await this.getDisplayName(); - const { data, meta } = await this._source.getGeoJsonWithMeta({ - layerName, - }, searchFilters); + const { data, meta } = await this._source.getGeoJsonWithMeta(layerName, searchFilters); stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, data, meta); return { refreshed: true, diff --git a/x-pack/plugins/maps/public/shared/utils/color_utils.js b/x-pack/plugins/maps/public/shared/utils/color_utils.js index 1432538f78b85..862044ff021ee 100644 --- a/x-pack/plugins/maps/public/shared/utils/color_utils.js +++ b/x-pack/plugins/maps/public/shared/utils/color_utils.js @@ -20,4 +20,4 @@ export function getRGBColorRangeStrings(colorName, numberColors) { export function getHexColorRangeStrings(colorName, numberColors) { return getRGBColorRangeStrings(colorName, numberColors) .map(rgbColor => chroma(rgbColor).hex()); -} \ No newline at end of file +} diff --git a/x-pack/plugins/maps/public/store/map.js b/x-pack/plugins/maps/public/store/map.js index 4365af21d2044..0601d5efaaea2 100644 --- a/x-pack/plugins/maps/public/store/map.js +++ b/x-pack/plugins/maps/public/store/map.js @@ -94,6 +94,7 @@ const INITIAL_STATE = { mouseCoordinates: null, timeFilters: null, query: null, + filters: [], refreshConfig: null, refreshTimerLastTriggeredAt: null, }, @@ -196,13 +197,14 @@ export function map(state = INITIAL_STATE, action) { }; return { ...state, mapState: { ...state.mapState, ...newMapState } }; case SET_QUERY: - const { query, timeFilters } = action; + const { query, timeFilters, filters } = action; return { ...state, mapState: { ...state.mapState, query, timeFilters, + filters, } }; case SET_REFRESH_CONFIG: diff --git a/x-pack/plugins/maps/public/store/non_serializable_instances.js b/x-pack/plugins/maps/public/store/non_serializable_instances.js index bcc056faec90b..5aa5298b29547 100644 --- a/x-pack/plugins/maps/public/store/non_serializable_instances.js +++ b/x-pack/plugins/maps/public/store/non_serializable_instances.js @@ -19,12 +19,14 @@ function createInspectorAdapters() { return inspectorAdapters; } -const INITIAL_STATE = { - inspectorAdapters: createInspectorAdapters(), -}; - // Reducer -export function nonSerializableInstances(state = INITIAL_STATE) { +export function nonSerializableInstances(state) { + if (!state) { + return { + inspectorAdapters: createInspectorAdapters(), + }; + } + // state is read only and provides access to non-serializeable object instances return state; } diff --git a/x-pack/plugins/maps/public/store/ui.js b/x-pack/plugins/maps/public/store/ui.js index 30f526786ed90..7804fe26b6fe5 100644 --- a/x-pack/plugins/maps/public/store/ui.js +++ b/x-pack/plugins/maps/public/store/ui.js @@ -69,6 +69,12 @@ export function enableFullScreen() { isFullScreen: true }; } +export function setReadOnly(isReadOnly) { + return { + type: SET_READ_ONLY, + isReadOnly + }; +} // Selectors export const getFlyoutDisplay = ({ ui }) => ui && ui.flyoutDisplay diff --git a/x-pack/plugins/maps/server/maps_telemetry/maps_telemetry.test.js b/x-pack/plugins/maps/server/maps_telemetry/maps_telemetry.test.js index 0d11ff7f8c373..d2f7b47577005 100644 --- a/x-pack/plugins/maps/server/maps_telemetry/maps_telemetry.test.js +++ b/x-pack/plugins/maps/server/maps_telemetry/maps_telemetry.test.js @@ -85,4 +85,4 @@ describe('buildMapsTelemetry', () => { 'mapsTotalCount': 3 }); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/maps/server/maps_telemetry/maps_usage_collector.js b/x-pack/plugins/maps/server/maps_telemetry/maps_usage_collector.js index 48c49542580c6..88713a4471123 100644 --- a/x-pack/plugins/maps/server/maps_telemetry/maps_usage_collector.js +++ b/x-pack/plugins/maps/server/maps_telemetry/maps_usage_collector.js @@ -54,4 +54,4 @@ export function registerMapsUsageCollector(server) { const mapsUsageCollector = server.usage.collectorSet .makeUsageCollector(collectorObj); server.usage.collectorSet.register(mapsUsageCollector); -} \ No newline at end of file +} diff --git a/x-pack/plugins/maps/server/maps_telemetry/maps_usage_collector.test.js b/x-pack/plugins/maps/server/maps_telemetry/maps_usage_collector.test.js index 073927ffd5bbf..186eb41bca8a2 100644 --- a/x-pack/plugins/maps/server/maps_telemetry/maps_usage_collector.test.js +++ b/x-pack/plugins/maps/server/maps_telemetry/maps_usage_collector.test.js @@ -66,4 +66,4 @@ describe('buildCollectorObj#fetch', () => { await expect(fetch()).rejects.toMatchObject(new Error('Sad violin')); }); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/maps/server/maps_telemetry/telemetry_task.test.js b/x-pack/plugins/maps/server/maps_telemetry/telemetry_task.test.js index e8b04b15b1e20..58d53d35260c7 100644 --- a/x-pack/plugins/maps/server/maps_telemetry/telemetry_task.test.js +++ b/x-pack/plugins/maps/server/maps_telemetry/telemetry_task.test.js @@ -40,4 +40,4 @@ describe('telemetryTaskRunner', () => { }, }); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/maps/server/test_utils/index.js b/x-pack/plugins/maps/server/test_utils/index.js index 8a11d233f1d48..3de792e79c9e3 100644 --- a/x-pack/plugins/maps/server/test_utils/index.js +++ b/x-pack/plugins/maps/server/test_utils/index.js @@ -48,4 +48,4 @@ export const getMockKbnServer = ( }, config: () => ({ get: () => '' }), log: () => undefined -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/ml/public/components/anomalies_table/anomalies_table_columns.js b/x-pack/plugins/ml/public/components/anomalies_table/anomalies_table_columns.js index b45d65b2f56f6..ff2c61d3030a4 100644 --- a/x-pack/plugins/ml/public/components/anomalies_table/anomalies_table_columns.js +++ b/x-pack/plugins/ml/public/components/anomalies_table/anomalies_table_columns.js @@ -171,7 +171,7 @@ export function getColumns( }), render: (actual, item) => { const fieldFormat = mlFieldFormatService.getFieldFormat(item.jobId, item.source.detector_index); - return formatValue(item.actual, item.source.function, fieldFormat); + return formatValue(item.actual, item.source.function, fieldFormat, item.source); }, sortable: true }); @@ -185,7 +185,7 @@ export function getColumns( }), render: (typical, item) => { const fieldFormat = mlFieldFormatService.getFieldFormat(item.jobId, item.source.detector_index); - return formatValue(item.typical, item.source.function, fieldFormat); + return formatValue(item.typical, item.source.function, fieldFormat, item.source); }, sortable: true }); diff --git a/x-pack/plugins/ml/public/components/anomalies_table/anomaly_details.js b/x-pack/plugins/ml/public/components/anomalies_table/anomaly_details.js index 7bbc59dddad5b..cc47a83eda597 100644 --- a/x-pack/plugins/ml/public/components/anomalies_table/anomaly_details.js +++ b/x-pack/plugins/ml/public/components/anomalies_table/anomaly_details.js @@ -152,7 +152,7 @@ function getDetailsItems(anomaly, examples, filter) { title: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.actualTitle', { defaultMessage: 'actual', }), - description: formatValue(anomaly.actual, source.function) + description: formatValue(anomaly.actual, source.function, undefined, source) }); } @@ -161,7 +161,7 @@ function getDetailsItems(anomaly, examples, filter) { title: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.typicalTitle', { defaultMessage: 'typical', }), - description: formatValue(anomaly.typical, source.function) + description: formatValue(anomaly.typical, source.function, undefined, source) }); } diff --git a/x-pack/plugins/ml/public/components/chart_tooltip/index.js b/x-pack/plugins/ml/public/components/chart_tooltip/index.js index dce4cc44e2526..2349bc3986022 100644 --- a/x-pack/plugins/ml/public/components/chart_tooltip/index.js +++ b/x-pack/plugins/ml/public/components/chart_tooltip/index.js @@ -6,4 +6,4 @@ -import './chart_tooltip'; \ No newline at end of file +import './chart_tooltip'; diff --git a/x-pack/plugins/ml/public/components/controls/select_interval/__tests__/select_interval_directive.js b/x-pack/plugins/ml/public/components/controls/select_interval/__tests__/select_interval_directive.js new file mode 100644 index 0000000000000..aa18b75e26d2e --- /dev/null +++ b/x-pack/plugins/ml/public/components/controls/select_interval/__tests__/select_interval_directive.js @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from 'expect.js'; +import ngMock from 'ng_mock'; + +import { interval$ } from '../select_interval'; + +describe('ML - mlSelectIntervalService', () => { + let appState; + + beforeEach(ngMock.module('kibana', (stateManagementConfigProvider) => { + stateManagementConfigProvider.enable(); + })); + beforeEach(ngMock.module(($provide) => { + appState = { + fetch: () => {}, + save: () => {} + }; + + $provide.factory('AppState', () => () => appState); + })); + + it('initializes AppState with correct default value', (done) => { + ngMock.inject(($injector) => { + $injector.get('mlSelectIntervalService'); + const defaultValue = { display: 'Auto', val: 'auto' }; + + expect(appState.mlSelectInterval).to.eql(defaultValue); + expect(interval$.getValue()).to.eql(defaultValue); + + done(); + }); + }); + + it('restores AppState to interval$ observable', (done) => { + ngMock.inject(($injector) => { + const restoreValue = { display: '1 day', val: 'day' }; + appState.mlSelectInterval = restoreValue; + + $injector.get('mlSelectIntervalService'); + + expect(appState.mlSelectInterval).to.eql(restoreValue); + expect(interval$.getValue()).to.eql(restoreValue); + + done(); + }); + }); + +}); diff --git a/x-pack/plugins/ml/public/components/controls/select_interval/select_interval.js b/x-pack/plugins/ml/public/components/controls/select_interval/select_interval.js index 226aeccc39027..df622ff9e5ed6 100644 --- a/x-pack/plugins/ml/public/components/controls/select_interval/select_interval.js +++ b/x-pack/plugins/ml/public/components/controls/select_interval/select_interval.js @@ -9,6 +9,8 @@ /* * React component for rendering a select element with various aggregation interval levels. */ + +import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { BehaviorSubject } from 'rxjs'; @@ -53,9 +55,13 @@ function optionValueToInterval(value) { return interval; } -export const interval$ = new BehaviorSubject(OPTIONS[0]); +export const interval$ = new BehaviorSubject(optionValueToInterval(OPTIONS[0].value)); class SelectIntervalUnwrapped extends Component { + static propTypes = { + interval: PropTypes.object.isRequired, + }; + onChange = (e) => { const interval = optionValueToInterval(e.target.value); interval$.next(interval); @@ -66,7 +72,7 @@ class SelectIntervalUnwrapped extends Component { ); diff --git a/x-pack/plugins/ml/public/components/controls/select_interval/select_interval.test.js b/x-pack/plugins/ml/public/components/controls/select_interval/select_interval.test.js new file mode 100644 index 0000000000000..b8dff4a8f4755 --- /dev/null +++ b/x-pack/plugins/ml/public/components/controls/select_interval/select_interval.test.js @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { SelectInterval } from './select_interval'; + +describe('SelectInterval', () => { + + test('creates correct initial selected value', () => { + const wrapper = shallowWithIntl(); + const defaultSelectedValue = wrapper.props().interval.val; + + expect(defaultSelectedValue).toBe('auto'); + }); + + test('currently selected value is updated correctly on click', () => { + const wrapper = shallowWithIntl(); + const select = wrapper.first().shallow(); + + const defaultSelectedValue = wrapper.props().interval.val; + expect(defaultSelectedValue).toBe('auto'); + + select.simulate('change', { target: { value: 'day' } }); + const updatedSelectedValue = wrapper.props().interval.val; + expect(updatedSelectedValue).toBe('day'); + }); + +}); diff --git a/x-pack/plugins/ml/public/components/field_title_bar/index.js b/x-pack/plugins/ml/public/components/field_title_bar/index.js index 0fb644de342fc..010cc916702a0 100644 --- a/x-pack/plugins/ml/public/components/field_title_bar/index.js +++ b/x-pack/plugins/ml/public/components/field_title_bar/index.js @@ -6,4 +6,4 @@ -import './field_title_bar_directive'; \ No newline at end of file +import './field_title_bar_directive'; diff --git a/x-pack/plugins/ml/public/components/form_label/index.js b/x-pack/plugins/ml/public/components/form_label/index.js index 4d4a0f7703a91..5218ee55c6062 100644 --- a/x-pack/plugins/ml/public/components/form_label/index.js +++ b/x-pack/plugins/ml/public/components/form_label/index.js @@ -6,4 +6,4 @@ -import './form_label_directive'; \ No newline at end of file +import './form_label_directive'; diff --git a/x-pack/plugins/ml/public/components/job_group_select/index.js b/x-pack/plugins/ml/public/components/job_group_select/index.js index ae7894b6f29c0..0704e47bf7da6 100644 --- a/x-pack/plugins/ml/public/components/job_group_select/index.js +++ b/x-pack/plugins/ml/public/components/job_group_select/index.js @@ -6,4 +6,4 @@ -import './job_group_select'; \ No newline at end of file +import './job_group_select'; diff --git a/x-pack/plugins/ml/public/components/job_select_list/index.js b/x-pack/plugins/ml/public/components/job_select_list/index.js index b826021fe85f1..bba2809644d84 100644 --- a/x-pack/plugins/ml/public/components/job_select_list/index.js +++ b/x-pack/plugins/ml/public/components/job_select_list/index.js @@ -9,4 +9,4 @@ import './job_select_list_directive'; import './job_select_button_directive.js'; -import './job_select_service.js'; \ No newline at end of file +import './job_select_service.js'; diff --git a/x-pack/plugins/ml/public/formatters/__tests__/format_value.js b/x-pack/plugins/ml/public/formatters/__tests__/format_value.js index ff5548b73551e..69362e76ceced 100644 --- a/x-pack/plugins/ml/public/formatters/__tests__/format_value.js +++ b/x-pack/plugins/ml/public/formatters/__tests__/format_value.js @@ -7,23 +7,55 @@ import expect from 'expect.js'; -import moment from 'moment'; +import moment from 'moment-timezone'; import { formatValue } from '../format_value'; describe('ML - formatValue formatter', () => { + const timeOfWeekRecord = { + job_id: 'gallery_time_of_week', + result_type: 'record', + probability: 0.012818, + record_score: 53.55134, + bucket_span: 900, + detector_index: 0, + timestamp: 1530155700000, + by_field_name: 'clientip', + by_field_value: '65.55.215.39', + function: 'time_of_week', + function_description: 'time' + }; - // Just check the return value is in the expected format, and - // not the exact value as this will be timezone specific. + const timeOfDayRecord = { + job_id: 'gallery_time_of_day', + result_type: 'record', + probability: 0.012818, + record_score: 97.94245, + bucket_span: 900, + detector_index: 0, + timestamp: 1517472900000, + by_field_name: 'clientip', + by_field_value: '157.56.93.83', + function: 'time_of_day', + function_description: 'time' + }; + + // Set timezone to US/Eastern for time_of_day and time_of_week tests. + beforeEach(() => { + moment.tz.setDefault('US/Eastern'); + }); + + afterEach(() => { + moment.tz.setDefault('Browser'); + }); + + // For time_of_day and time_of_week test values which are offsets in seconds + // from UTC start of week / day are formatted correctly using the test timezone. it('correctly formats time_of_week value from numeric input', () => { - const formattedValue = formatValue(1483228800, 'time_of_week'); - const result = moment(formattedValue, 'ddd hh:mm', true).isValid(); - expect(result).to.be(true); + expect(formatValue(359739, 'time_of_week', undefined, timeOfWeekRecord)).to.be('Wed 23:55'); }); it('correctly formats time_of_day value from numeric input', () => { - const formattedValue = formatValue(1483228800, 'time_of_day'); - const result = moment(formattedValue, 'hh:mm', true).isValid(); - expect(result).to.be(true); + expect(formatValue(73781, 'time_of_day', undefined, timeOfDayRecord)).to.be('15:29'); }); it('correctly formats number values from numeric input', () => { @@ -37,15 +69,11 @@ describe('ML - formatValue formatter', () => { }); it('correctly formats time_of_week value from array input', () => { - const formattedValue = formatValue([1483228800], 'time_of_week'); - const result = moment(formattedValue, 'ddd hh:mm', true).isValid(); - expect(result).to.be(true); + expect(formatValue([359739], 'time_of_week', undefined, timeOfWeekRecord)).to.be('Wed 23:55'); }); it('correctly formats time_of_day value from array input', () => { - const formattedValue = formatValue([1483228800], 'time_of_day'); - const result = moment(formattedValue, 'hh:mm', true).isValid(); - expect(result).to.be(true); + expect(formatValue([73781], 'time_of_day', undefined, timeOfDayRecord)).to.be('15:29'); }); it('correctly formats number values from array input', () => { diff --git a/x-pack/plugins/ml/public/formatters/format_value.js b/x-pack/plugins/ml/public/formatters/format_value.js index da6eeba608b1b..800eb9dc48af6 100644 --- a/x-pack/plugins/ml/public/formatters/format_value.js +++ b/x-pack/plugins/ml/public/formatters/format_value.js @@ -24,42 +24,54 @@ const SIGFIGS_IF_ROUNDING = 3; // Number of sigfigs to use for values < 10 // Formats the value of an actual or typical field from a machine learning anomaly record. // mlFunction is the 'function' field from the ML record containing what the user entered e.g. 'high_count', // (as opposed to the 'function_description' field which holds an ML-built display hint for the function e.g. 'count'. -export function formatValue(value, mlFunction, fieldFormat) { +// If a Kibana fieldFormat is not supplied, will fall back to default +// formatting depending on the magnitude of the value. +// For time_of_day or time_of_week functions the anomaly record +// containing the timestamp of the anomaly should be supplied in +// order to correctly format the day or week offset to the time of the anomaly. +export function formatValue(value, mlFunction, fieldFormat, record) { // actual and typical values in anomaly record results will be arrays. // Unless the array is multi-valued (as it will be for multi-variate analyses such as lat_long), // simply return the formatted single value. if (Array.isArray(value)) { if (value.length === 1) { - return formatSingleValue(value[0], mlFunction, fieldFormat); + return formatSingleValue(value[0], mlFunction, fieldFormat, record); } else { // Return with array style formatting. - const values = value.map(val => formatSingleValue(val, mlFunction, fieldFormat)); + const values = value.map(val => formatSingleValue(val, mlFunction, fieldFormat, record)); return `[${values}]`; } } else { - return formatSingleValue(value, mlFunction, fieldFormat); + return formatSingleValue(value, mlFunction, fieldFormat, record); } } // Formats a single value according to the specified ML function. // If a Kibana fieldFormat is not supplied, will fall back to default // formatting depending on the magnitude of the value. -function formatSingleValue(value, mlFunction, fieldFormat) { +// For time_of_day or time_of_week functions the anomaly record +// containing the timestamp of the anomaly should be supplied in +// order to correctly format the day or week offset to the time of the anomaly. +function formatSingleValue(value, mlFunction, fieldFormat, record) { if (value === undefined || value === null) { return ''; } // If the analysis function is time_of_week/day, format as day/time. + // For time_of_week / day, actual / typical is the UTC offset in seconds from the + // start of the week / day, so need to manipulate to UTC moment of the start of the week / day + // that the anomaly occurred using record timestamp if supplied, add on the offset, and finally + // revert back to configured timezone for formatting. if (mlFunction === 'time_of_week') { - const d = new Date(); + const d = ((record !== undefined && record.timestamp !== undefined) ? new Date(record.timestamp) : new Date()); const i = parseInt(value); - d.setTime(i * 1000); - return moment(d).format('ddd hh:mm'); + const utcMoment = moment.utc(d).startOf('week').add(i, 's'); + return moment(utcMoment.valueOf()).format('ddd HH:mm'); } else if (mlFunction === 'time_of_day') { - const d = new Date(); + const d = ((record !== undefined && record.timestamp !== undefined) ? new Date(record.timestamp) : new Date()); const i = parseInt(value); - d.setTime(i * 1000); - return moment(d).format('hh:mm'); + const utcMoment = moment.utc(d).startOf('day').add(i, 's'); + return moment(utcMoment.valueOf()).format('HH:mm'); } else { if (fieldFormat !== undefined) { return fieldFormat.convert(value, 'text'); diff --git a/x-pack/plugins/ml/public/jobs/new_job/advanced/new_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/advanced/new_job_controller.js index 4613467f0dabb..5b131a9dbd924 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/advanced/new_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/advanced/new_job_controller.js @@ -519,6 +519,7 @@ module.controller('MlNewJob', values: { jobId: $scope.job.job_id } }); changeTab({ index: 0 }); + $scope.$applyAsync(); } else { checkInfluencers(); } diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_estimator/bucket_span_estimator_directive.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_estimator/bucket_span_estimator_directive.js index 7bb6238354c54..92266ecb31c1e 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_estimator/bucket_span_estimator_directive.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_estimator/bucket_span_estimator_directive.js @@ -60,7 +60,6 @@ module.directive('mlBucketSpanEstimator', function (i18n) { end: $scope.formConfig.end }, fields: [], - filters: $scope.formConfig.filters, index: $scope.formConfig.indexPattern.title, query: $scope.formConfig.combinedQuery, splitField: $scope.formConfig.splitField && $scope.formConfig.splitField.name, diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_selection/index.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_selection/index.js index 9a1074cfd194b..43a983f130597 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_selection/index.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_selection/index.js @@ -6,4 +6,4 @@ -import './bucket_span_selection_directive'; \ No newline at end of file +import './bucket_span_selection_directive'; diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/event_rate_chart/index.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/event_rate_chart/index.js index cdd3519f6c185..bca1980cec452 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/components/event_rate_chart/index.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/event_rate_chart/index.js @@ -6,4 +6,4 @@ -import './event_rate_chart_directive'; \ No newline at end of file +import './event_rate_chart_directive'; diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/fields_selection/index.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/fields_selection/index.js index 3749313194992..a9ce6a6d99715 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/components/fields_selection/index.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/fields_selection/index.js @@ -6,4 +6,4 @@ -import './fields_selection_directive'; \ No newline at end of file +import './fields_selection_directive'; diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/general_job_details/index.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/general_job_details/index.js index fee5c486f4566..c8d701ce8477c 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/components/general_job_details/index.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/general_job_details/index.js @@ -6,4 +6,4 @@ -import './general_job_details_directive'; \ No newline at end of file +import './general_job_details_directive'; diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_controller.js index d32143a62ef74..57c413f0dc4a5 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_controller.js @@ -114,8 +114,6 @@ module const { indexPattern, savedSearch, - query, - filters, combinedQuery } = createSearchItems(); timeBasedIndexCheck(indexPattern, true); @@ -232,8 +230,6 @@ module influencerFields: [], firstSplitFieldName: undefined, indexPattern, - query, - filters, combinedQuery, usesSavedSearch: (savedSearch.id !== undefined), jobId: '', diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_controller.js index 02328817e5878..9c7985f106f5b 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_controller.js @@ -114,8 +114,6 @@ module const { indexPattern, savedSearch, - query, - filters, combinedQuery } = createSearchItems(); timeBasedIndexCheck(indexPattern, true); @@ -236,8 +234,6 @@ module influencerFields: [], firstSplitFieldName: undefined, indexPattern: indexPattern, - query, - filters, combinedQuery, usesSavedSearch: (savedSearch.id !== undefined), jobId: '', diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js index ab29cd3410c97..9522115367116 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js @@ -87,7 +87,6 @@ module const { indexPattern, savedSearch, - query, combinedQuery } = createSearchItems(); const pageTitle = (savedSearch.id !== undefined) ? @@ -145,8 +144,6 @@ module kibanaObjects: {}, start: 0, end: 0, - query, - filters: [], useFullIndexData: true, startDatafeedAfterSave: true, useDedicatedIndex: false, @@ -157,7 +154,6 @@ module $scope.resetJob = function () { $scope.overallState = SAVE_STATE.NOT_SAVED; $scope.formConfig.jobs = []; - $scope.formConfig.filters = []; $scope.formConfig.kibanaObjects = {}; loadJobConfigs(); diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_controller.js index 30c2a8e821261..89c7e170d1319 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_controller.js @@ -120,8 +120,6 @@ module const { indexPattern, savedSearch, - query, - filters, combinedQuery } = createSearchItems(); timeBasedIndexCheck(indexPattern, true); @@ -243,8 +241,6 @@ module timeField: indexPattern.timeFieldName, indexPattern: undefined, usesSavedSearch: (savedSearch.id !== undefined), - query, - filters, combinedQuery, jobId: '', description: '', diff --git a/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js b/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js index 4f8bd35abda29..d1a71feff8999 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js +++ b/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js @@ -20,24 +20,23 @@ export function SearchItemsProvider(Private, $route, config) { function createSearchItems() { let indexPattern = $route.current.locals.indexPattern; + // query is only used by the data visualizer as it needs + // a lucene query_string. + // Using a blank query will cause match_all:{} to be used + // when passed through luceneStringToDsl let query = { - query: '*', + query: '', language: 'lucene' }; let combinedQuery = { bool: { must: [{ - query_string: { - analyze_wildcard: true, - query: '*' - } + match_all: {} }] } }; - let filters = []; - const savedSearch = $route.current.locals.savedSearch; if (indexPattern.id === undefined && savedSearch.id !== undefined) { const searchSource = savedSearch.searchSource; @@ -46,9 +45,8 @@ export function SearchItemsProvider(Private, $route, config) { query = searchSource.getField('query'); const fs = searchSource.getField('filter'); - if (fs.length) { - filters = fs; - } + const filters = (fs.length) ? fs : []; + const esQueryConfigs = getEsQueryConfig(config); combinedQuery = buildEsQuery(indexPattern, [query], filters, esQueryConfigs); } @@ -56,9 +54,8 @@ export function SearchItemsProvider(Private, $route, config) { return { indexPattern, savedSearch, - filters, query, - combinedQuery + combinedQuery, }; } diff --git a/x-pack/plugins/ml/public/settings/filter_lists/edit/index.js b/x-pack/plugins/ml/public/settings/filter_lists/edit/index.js index 5913b7ef60495..3839017291326 100644 --- a/x-pack/plugins/ml/public/settings/filter_lists/edit/index.js +++ b/x-pack/plugins/ml/public/settings/filter_lists/edit/index.js @@ -5,4 +5,4 @@ */ -import './directive'; \ No newline at end of file +import './directive'; diff --git a/x-pack/plugins/ml/public/settings/filter_lists/index.js b/x-pack/plugins/ml/public/settings/filter_lists/index.js index 3e610e6e8ddf0..463b602c20c9a 100644 --- a/x-pack/plugins/ml/public/settings/filter_lists/index.js +++ b/x-pack/plugins/ml/public/settings/filter_lists/index.js @@ -6,4 +6,4 @@ import './edit'; -import './list'; \ No newline at end of file +import './list'; diff --git a/x-pack/plugins/ml/public/timeseriesexplorer/components/forecasting_modal/index.js b/x-pack/plugins/ml/public/timeseriesexplorer/components/forecasting_modal/index.js index 7f8ea9db3b501..81e2e7a830297 100644 --- a/x-pack/plugins/ml/public/timeseriesexplorer/components/forecasting_modal/index.js +++ b/x-pack/plugins/ml/public/timeseriesexplorer/components/forecasting_modal/index.js @@ -6,4 +6,4 @@ -import './forecasting_modal_directive'; \ No newline at end of file +import './forecasting_modal_directive'; diff --git a/x-pack/plugins/ml/server/client/call_with_request_factory.js b/x-pack/plugins/ml/server/client/call_with_request_factory.js index 321f647dbe0ae..c7aa44b14dca9 100644 --- a/x-pack/plugins/ml/server/client/call_with_request_factory.js +++ b/x-pack/plugins/ml/server/client/call_with_request_factory.js @@ -10,10 +10,7 @@ import { once } from 'lodash'; import { elasticsearchJsPlugin } from './elasticsearch_ml'; const callWithRequest = once((server) => { - const config = { - plugins: [ elasticsearchJsPlugin ], - ...server.config().get('elasticsearch') - }; + const config = { plugins: [ elasticsearchJsPlugin ] }; const cluster = server.plugins.elasticsearch.createCluster('ml', config); return cluster.callWithRequest; diff --git a/x-pack/plugins/ml/server/models/bucket_span_estimator/__tests__/bucket_span_estimator.js b/x-pack/plugins/ml/server/models/bucket_span_estimator/__tests__/bucket_span_estimator.js index 73eb57f5e4b69..06a937ed68acc 100644 --- a/x-pack/plugins/ml/server/models/bucket_span_estimator/__tests__/bucket_span_estimator.js +++ b/x-pack/plugins/ml/server/models/bucket_span_estimator/__tests__/bucket_span_estimator.js @@ -62,11 +62,10 @@ const formConfig = { aggTypes: ['count'], duration: {}, fields: [null], - filters: [], index: '', query: { bool: { - must: [{ query_string: { analyze_wildcard: true, query: '*' } }], + must: [{ match_all: {} }], must_not: [] } } diff --git a/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.js b/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.js index 0013971fcdb97..4166a9579b3c1 100644 --- a/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.js +++ b/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.js @@ -317,10 +317,6 @@ export function estimateBucketSpanFactory(callWithRequest, server) { throw new Error('Invalid formConfig: Missing fields.'); } - if (typeof formConfig.filters === 'undefined') { - throw new Error('Invalid formConfig: Missing filters.'); - } - if (typeof formConfig.query === 'undefined') { throw new Error('Invalid formConfig: Missing query.'); } diff --git a/x-pack/plugins/ml/server/models/job_validation/validate_bucket_span.js b/x-pack/plugins/ml/server/models/job_validation/validate_bucket_span.js index 2d11f7ed60362..6dd9ea34ce433 100644 --- a/x-pack/plugins/ml/server/models/job_validation/validate_bucket_span.js +++ b/x-pack/plugins/ml/server/models/job_validation/validate_bucket_span.js @@ -88,7 +88,6 @@ export async function validateBucketSpan(callWithRequest, job, duration, server) aggTypes: [], duration, fields: [], - filters: [], index: job.datafeed_config.indices.join(','), query: wrapQuery(job.datafeed_config.query), splitField: undefined, diff --git a/x-pack/plugins/monitoring/README.md b/x-pack/plugins/monitoring/README.md index 519b3f835d918..a161fb0180a10 100644 --- a/x-pack/plugins/monitoring/README.md +++ b/x-pack/plugins/monitoring/README.md @@ -35,28 +35,6 @@ Add a `debugger` line to create a breakpoint, and then: gulp sync && mocha debug --compilers js:babel-register /pathto/kibana/plugins/monitoring/pathto/__tests__/testfile.js ``` -## Deploying - -Monitoring is part of XPack, and only a single XPack artifact needs to be -deployed. Previously, the instructions to deploy were: - -> The `release task` creates archives and uploads them to -download.elasticsearch.org/elasticsearch/monitoring/VERSION. You will need S3 -credentials in `$HOME/.aws-config.json`. Format as so: - -> ``` -> { -> "key":"MY_KEY_HERE", -> "secret":"your/long/secret/string" -> } -> ``` - -> To upload the current archive as the "latest" release, use: - -> ``` -> gulp release -> ``` - ## Multicluster Setup for Development To run the UI with multiple clusters, the easiest way is to run 2 nodes out of diff --git a/x-pack/plugins/monitoring/common/constants.js b/x-pack/plugins/monitoring/common/constants.js index d87bb2c8be8fe..42956c2a352d3 100644 --- a/x-pack/plugins/monitoring/common/constants.js +++ b/x-pack/plugins/monitoring/common/constants.js @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; /** * Helper string to add as a tag in every logging call */ -export const LOGGING_TAG = 'monitoring-ui'; +export const LOGGING_TAG = 'monitoring'; /** * Helper string to add as a tag in every logging call related to Kibana monitoring */ diff --git a/x-pack/plugins/monitoring/init.js b/x-pack/plugins/monitoring/init.js index 24aecb4a604d3..b85a402af5ed8 100644 --- a/x-pack/plugins/monitoring/init.js +++ b/x-pack/plugins/monitoring/init.js @@ -85,8 +85,6 @@ export const init = (monitoringPlugin, server) => { maxBucketSize: config.get('xpack.monitoring.max_bucket_size'), minIntervalSeconds: config.get('xpack.monitoring.min_interval_seconds'), kbnIndex: config.get('kibana.index'), - esApiVersion: config.get('elasticsearch.apiVersion'), - esShardTimeout: config.get('elasticsearch.shardTimeout'), showLicenseExpiration: config.get('xpack.monitoring.show_license_expiration'), showCgroupMetricsElasticsearch: config.get('xpack.monitoring.ui.container.elasticsearch.enabled'), showCgroupMetricsLogstash: config.get('xpack.monitoring.ui.container.logstash.enabled') // Note, not currently used, but see https://github.com/elastic/x-pack-kibana/issues/1559 part 2 diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js index 94e540222d53d..cf80f1771317f 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js @@ -29,4 +29,4 @@ export const vents = { }); } } -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js index 112bd9f5000e1..887e7fd678fdc 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js @@ -33,4 +33,4 @@ describe('Config class', () => { config.update(configJson); expect(graphUpdateSpy.calledWith(configJson.graph)).to.be(true); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js index 15bd00cbf9220..1a734debc21ec 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js @@ -35,4 +35,4 @@ describe('PipelineState class', () => { pipelineState.update(configJson); expect(configUpdateSpy.calledWith(configJson.representation)).to.be(true); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js index cfe240436b550..a1abcf6385f7e 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js @@ -31,4 +31,4 @@ describe('BooleanEdge', () => { const booleanEdge = new BooleanEdge(graph, edgeJson); expect(booleanEdge).to.be.a(Edge); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js index 35249d938f2e5..00105ce32703d 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js @@ -36,4 +36,4 @@ describe('Edge', () => { expect(edge.toId).to.be('myes'); expect(edge.to).to.be(graph.verticesById.myes); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js index 27bc53673f036..cb9b831f4e351 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js @@ -42,4 +42,4 @@ describe('edgeFactory', () => { const fn = () => edgeFactory(graph, edgeJson); expect(fn).to.throwError(); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js index a1f875f9ee585..4b98217e1817d 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js @@ -38,4 +38,4 @@ describe('IfVertex', () => { const ifVertex = new IfVertex(graph, vertexJson); expect(ifVertex.iconType).to.be('logstashIf'); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js index 27d2e2704f10b..eb091e6bdf683 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js @@ -26,4 +26,4 @@ describe('QueueVertex', () => { const queueVertex = new QueueVertex(graph, vertexJson); expect(queueVertex.typeString).to.be('queue'); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js index 89cb4916fcad9..5cb914a5e4210 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js @@ -46,4 +46,4 @@ describe('vertexFactory', () => { const fn = () => vertexFactory(graph, vertexJson); expect(fn).to.throwError(); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js index 7ddf7cd4f235c..a9c745213642d 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js @@ -17,4 +17,4 @@ export function edgeFactory(graph, edgeJson) { default: throw new Error(`Unknown edge type ${type}! This shouldn't happen!`); } -} \ No newline at end of file +} diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js index aa0198e16cea6..96876b87abfc0 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js @@ -20,4 +20,4 @@ export function vertexFactory(graph, vertexJson) { default: throw new Error(`Unknown vertex type ${type}! This shouldn't happen!`); } -} \ No newline at end of file +} diff --git a/x-pack/plugins/monitoring/server/es_client/__tests__/instantiate_client.js b/x-pack/plugins/monitoring/server/es_client/__tests__/instantiate_client.js index 143f510326e41..bb11902f1ff6d 100644 --- a/x-pack/plugins/monitoring/server/es_client/__tests__/instantiate_client.js +++ b/x-pack/plugins/monitoring/server/es_client/__tests__/instantiate_client.js @@ -24,15 +24,6 @@ function getMockServerFromConnectionUrl(monitoringClusterUrl) { } } }, - elasticsearch: { - hosts: ['http://localhost:9200'], - username: 'user-internal-test', - password: 'p@ssw0rd!-internal-test', - ssl: {}, - customHeaders: { - 'x-custom-headers-test': 'connection-production' - } - } }; const config = () => { @@ -50,7 +41,6 @@ function getMockServerFromConnectionUrl(monitoringClusterUrl) { config: sinon.stub().returns(server.elasticsearch) }), createCluster: sinon.stub(), - ElasticsearchClientLogging: noop } }, events: { @@ -69,7 +59,7 @@ describe('Instantiate Client', () => { exposeClient(server); expect(server.log.getCall(0).args).to.eql([ - [ 'monitoring-ui', 'es-client' ], + [ 'monitoring', 'es-client' ], 'config sourced from: production cluster' ]); }); @@ -79,14 +69,14 @@ describe('Instantiate Client', () => { exposeClient(server); expect(server.log.getCall(0).args).to.eql([ - [ 'monitoring-ui', 'es-client' ], + [ 'monitoring', 'es-client' ], 'config sourced from: monitoring cluster' ]); }); }); describe('Custom Headers Configuration', () => { - it('Adds xpack.monitoring.elasticsearch.customHeaders if connected to production cluster', () => { + it('Does not add xpack.monitoring.elasticsearch.customHeaders if connected to production cluster', () => { const server = getMockServerFromConnectionUrl(null); // pass null for URL to create the client using prod config exposeClient(server); @@ -96,9 +86,7 @@ describe('Instantiate Client', () => { sinon.assert.calledOnce(createCluster); expect(createClusterCall.args[0]).to.be('monitoring'); - expect(createClusterCall.args[1].customHeaders).to.eql( - { 'x-custom-headers-test': 'connection-production' } - ); + expect(createClusterCall.args[1].customHeaders).to.eql(undefined); }); it('Adds xpack.monitoring.elasticsearch.customHeaders if connected to monitoring cluster', () => { @@ -128,7 +116,7 @@ describe('Instantiate Client', () => { sinon.assert.calledOnce(createCluster); expect(createClusterCall.args[0]).to.be('monitoring'); - expect(createClientOptions.hosts[0]).to.eql('http://localhost:9200'); + expect(createClientOptions.hosts).to.eql(undefined); }); }); diff --git a/x-pack/plugins/monitoring/server/es_client/instantiate_client.js b/x-pack/plugins/monitoring/server/es_client/instantiate_client.js index 9ba5cdd9520d2..c52c1b3aa8290 100644 --- a/x-pack/plugins/monitoring/server/es_client/instantiate_client.js +++ b/x-pack/plugins/monitoring/server/es_client/instantiate_client.js @@ -15,33 +15,24 @@ import { LOGGING_TAG } from '../../common/constants'; */ export function exposeClient(server) { - const Logger = server.plugins.elasticsearch.ElasticsearchClientLogging; - const logQueries = Boolean(server.config().get('xpack.monitoring.elasticsearch.logQueries')); + const monitoringEsConfig = server.config().get('xpack.monitoring.elasticsearch'); - class MonitoringClientLogging extends Logger { - constructor() { - super(); - - this.tags = [LOGGING_TAG]; - this.logQueries = logQueries; - } - } - - let config = { - ...server.config().get('xpack.monitoring.elasticsearch') - }; - let configSource = 'monitoring'; - - if (!Boolean(config.hosts && config.hosts.length)) { - config = server.config().get('elasticsearch'); + let config; + let configSource; + if (!Boolean(monitoringEsConfig.hosts && monitoringEsConfig.hosts.length)) { + config = {}; configSource = 'production'; + } else { + config = { ...monitoringEsConfig }; + configSource = 'monitoring'; } - config.log = MonitoringClientLogging; - config.plugins = [monitoringBulk]; + const cluster = server.plugins.elasticsearch.createCluster('monitoring', { + ...config, + plugins: [monitoringBulk], + logQueries: Boolean(monitoringEsConfig.logQueries), + }); - const esPlugin = server.plugins.elasticsearch; - const cluster = esPlugin.createCluster('monitoring', config); server.events.on('stop', bindKey(cluster, 'close')); server.log([LOGGING_TAG, 'es-client'], `config sourced from: ${configSource} cluster`); diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js b/x-pack/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js index 2c6c52ed05ca6..6f7b6b3383538 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js @@ -32,20 +32,18 @@ describe('BulkUploader', () => { describe('registers a collector set and runs lifecycle events', () => { let server; beforeEach(() => { + const cluster = { + callWithInternalUser: sinon.stub().withArgs('monitoring.bulk').callsFake(() => { + return new Promise(resolve => setTimeout(resolve, CHECK_DELAY + 1)); + }), + }; + server = { log: sinon.spy(), plugins: { elasticsearch: { - getCluster: () => ({ - createClient: () => ({ - monitoring: { - bulk: function () { - return new Promise(resolve => setTimeout(resolve, CHECK_DELAY + 1)); - } - }, - }), - callWithInternalUser: sinon.spy(), // this tests internal collection and bulk upload, not HTTP API - }), + createCluster: () => cluster, + getCluster: () => cluster, }, }, usage: {}, @@ -74,15 +72,15 @@ describe('BulkUploader', () => { const loggingCalls = server.log.getCalls(); expect(loggingCalls.length).to.be.greaterThan(2); // should be 3-5: start, fetch, skip, fetch, skip expect(loggingCalls[0].args).to.eql([ - ['info', 'monitoring-ui', 'kibana-monitoring'], + ['info', 'monitoring', 'kibana-monitoring'], 'Starting monitoring stats collection', ]); expect(loggingCalls[1].args).to.eql([ - ['debug', 'monitoring-ui', 'kibana-monitoring'], + ['debug', 'monitoring', 'kibana-monitoring'], 'Skipping bulk uploading of an empty stats payload', ]); expect(loggingCalls[loggingCalls.length - 1].args).to.eql([ - ['info', 'monitoring-ui', 'kibana-monitoring'], + ['info', 'monitoring', 'kibana-monitoring'], 'Monitoring stats collection is stopped', ]); @@ -112,11 +110,11 @@ describe('BulkUploader', () => { // the last 2 logs as the call takes longer than this timeout (see the above mock) expect(loggingCalls.length).to.be(4); expect(loggingCalls[0].args).to.eql([ - ['info', 'monitoring-ui', 'kibana-monitoring'], + ['info', 'monitoring', 'kibana-monitoring'], 'Starting monitoring stats collection', ]); expect(loggingCalls[1].args).to.eql([ - ['debug', 'monitoring-ui', 'kibana-monitoring'], + ['debug', 'monitoring', 'kibana-monitoring'], 'Uploading bulk stats payload to the local cluster', ]); diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js b/x-pack/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js index b66617c6e5906..47566b0e5fc0a 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js @@ -48,7 +48,7 @@ export class BulkUploader { warn: message => server.log(['warning', ...LOGGING_TAGS], message) }; - this._client = server.plugins.elasticsearch.getCluster('admin').createClient({ + this._cluster = server.plugins.elasticsearch.createCluster('admin', { plugins: [monitoringBulk], }); @@ -121,7 +121,7 @@ export class BulkUploader { } _onPayload(payload) { - return sendBulkPayload(this._client, this._interval, payload); + return sendBulkPayload(this._cluster, this._interval, payload); } /* diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js b/x-pack/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js index 9202890f7a51c..e7b6ee3d9e3aa 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js @@ -10,8 +10,8 @@ import { KIBANA_SYSTEM_ID } from '../../../../xpack_main/common/constants'; /* * Send the Kibana usage data to the ES Monitoring Bulk endpoint */ -export function sendBulkPayload(client, interval, payload) { - return client.monitoring.bulk({ +export function sendBulkPayload(cluster, interval, payload) { + return cluster.callWithInternalUser('monitoring.bulk', { system_id: KIBANA_SYSTEM_ID, system_api_version: MONITORING_SYSTEM_API_VERSION, interval: interval + 'ms', diff --git a/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.js b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.js index 5cf4dade7153c..01c91e3c42278 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.js +++ b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.js @@ -35,4 +35,4 @@ export function createBeatsQuery(options = { }) { }); return createQuery(options); -} \ No newline at end of file +} diff --git a/x-pack/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js b/x-pack/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js index 90a01ff09576c..b5358a1f54787 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js +++ b/x-pack/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js @@ -59,7 +59,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found all non-basic cluster licenses. All clusters will be supported.' ); }); @@ -95,12 +95,12 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Detected all clusters in monitoring data have basic license. Checking for supported admin cluster UUID for Kibana kibana-1234.' ); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found basic license admin cluster UUID for Monitoring UI support: supported_cluster_uuid.' ); }); @@ -137,7 +137,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found some basic license clusters in monitoring data. Only non-basic will be supported.' ); }); @@ -177,7 +177,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found basic license admin cluster UUID for Monitoring UI support: supported_cluster_uuid.' ); }); @@ -212,7 +212,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found some basic license clusters in monitoring data. Only non-basic will be supported.' ); }); @@ -248,7 +248,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found all non-basic cluster licenses. All clusters will be supported.' ); }); @@ -271,7 +271,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found single cluster in monitoring data.' ); }); @@ -288,7 +288,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found single cluster in monitoring data.' ); }); @@ -306,7 +306,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found single cluster in monitoring data.' ); }); @@ -324,7 +324,7 @@ describe('Flag Supported Clusters', () => { ]); sinon.assert.calledWith( logStub, - ['debug', 'monitoring-ui', 'supported-clusters'], + ['debug', 'monitoring', 'supported-clusters'], 'Found single cluster in monitoring data.' ); }); diff --git a/x-pack/plugins/remote_clusters/index.js b/x-pack/plugins/remote_clusters/index.js index 9962899c08a63..ea5b19a0cf7a5 100644 --- a/x-pack/plugins/remote_clusters/index.js +++ b/x-pack/plugins/remote_clusters/index.js @@ -44,7 +44,12 @@ export function remoteClusters(kibana) { enabled: Joi.boolean().default(true), }).default(); }, - + isEnabled(config) { + return ( + config.get('xpack.remote_clusters.enabled') && + config.get('xpack.index_management.enabled') + ); + }, init: function (server) { registerLicenseChecker(server); registerListRoute(server); diff --git a/x-pack/plugins/remote_clusters/server/lib/license_pre_routing_factory/index.js b/x-pack/plugins/remote_clusters/server/lib/license_pre_routing_factory/index.js index a6903bcf11a78..0743e443955f4 100644 --- a/x-pack/plugins/remote_clusters/server/lib/license_pre_routing_factory/index.js +++ b/x-pack/plugins/remote_clusters/server/lib/license_pre_routing_factory/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { licensePreRoutingFactory } from './license_pre_routing_factory'; \ No newline at end of file +export { licensePreRoutingFactory } from './license_pre_routing_factory'; diff --git a/x-pack/plugins/reporting/common/constants.ts b/x-pack/plugins/reporting/common/constants.ts index 5268a1dd5329c..9cb93a5ed1017 100644 --- a/x-pack/plugins/reporting/common/constants.ts +++ b/x-pack/plugins/reporting/common/constants.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export const QUEUE_DOCTYPE = 'esqueue'; - export const JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY = 'xpack.reporting.jobCompletionNotifications'; diff --git a/x-pack/plugins/reporting/export_types/common/lib/screenshots.js b/x-pack/plugins/reporting/export_types/common/lib/screenshots.js index 9cf2b05400d3f..1bf3345c3827b 100644 --- a/x-pack/plugins/reporting/export_types/common/lib/screenshots.js +++ b/x-pack/plugins/reporting/export_types/common/lib/screenshots.js @@ -266,11 +266,6 @@ export function screenshotsObservableFactory(server) { browser => openUrl(browser, url, conditionalHeaders), browser => browser ), - tap(() => logger.debug('injecting custom css')), - mergeMap( - browser => injectCustomCss(browser, layout), - browser => browser - ), tap(() => logger.debug('waiting for elements or items count attribute; or not found to interrupt')), mergeMap( browser => Rx.race( @@ -294,6 +289,13 @@ export function screenshotsObservableFactory(server) { ({ browser, itemsCount }) => waitForElementsToBeInDOM(browser, itemsCount, layout), ({ browser, itemsCount }) => ({ browser, itemsCount }) ), + // Waiting till _after_ elements have rendered before injecting our CSS + // allows for them to be displayed properly in many cases + tap(() => logger.debug('injecting custom css')), + mergeMap( + ({ browser }) => injectCustomCss(browser, layout), + ({ browser }) => ({ browser }) + ), tap(() => logger.debug('positioning elements')), mergeMap( ({ browser }) => positionElements(browser, layout), diff --git a/x-pack/plugins/reporting/export_types/printable_pdf/server/create_job/compatibility_shim.js b/x-pack/plugins/reporting/export_types/printable_pdf/server/create_job/compatibility_shim.js index 18644b99cc4e9..68066d53186c8 100644 --- a/x-pack/plugins/reporting/export_types/printable_pdf/server/create_job/compatibility_shim.js +++ b/x-pack/plugins/reporting/export_types/printable_pdf/server/create_job/compatibility_shim.js @@ -78,4 +78,4 @@ export function compatibilityShimFactory(server) { return await createJob(transformedJobParams, headers, request); }; }; -} \ No newline at end of file +} diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.js b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.js index 00ede7644aeb0..12e829e97838e 100644 --- a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.js +++ b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.js @@ -15,7 +15,7 @@ import { args } from './args'; import { safeChildProcess } from '../../safe_child_process'; import { getChromeLogLocation } from '../paths'; -const compactWhitespace = (str) => { +const compactWhitespace = str => { return str.replace(/\s+/, ' '); }; @@ -48,8 +48,10 @@ export class HeadlessChromiumDriverFactory { TZ: browserTimezone, }, }) - .catch((error) => { - log(`The Reporting plugin encountered issues launching Chromium in a self-test. You may have trouble generating reports: ${error}`); + .catch(error => { + log( + `The Reporting plugin encountered issues launching Chromium in a self-test. You may have trouble generating reports: [${error}]` + ); log(`See Chromium's log output at "${getChromeLogLocation(this.binaryPath)}"`); return null; }); @@ -75,21 +77,24 @@ export class HeadlessChromiumDriverFactory { ignoreHTTPSErrors: true, args: chromiumArgs, env: { - TZ: browserTimezone + TZ: browserTimezone, }, }); page = await browser.newPage(); } catch (err) { - observer.error(new Error(`Error spawning Chromium browser: ${err}`)); + observer.error(new Error(`Error spawning Chromium browser: [${err}]`)); throw err; } - safeChildProcess({ - async kill() { - await browser.close(); - } - }, observer); + safeChildProcess( + { + async kill() { + await browser.close(); + }, + }, + observer + ); // Register with a few useful puppeteer event handlers: // https://pptr.dev/#?product=Puppeteer&version=v1.10.0&show=api-event-error @@ -105,25 +110,37 @@ export class HeadlessChromiumDriverFactory { partition(msg => msg.match(/\[\d+\/\d+.\d+:\w+:CONSOLE\(\d+\)\]/)) ); - const driver$ = Rx.of(new HeadlessChromiumDriver(page, { - maxScreenshotDimension: this.browserConfig.maxScreenshotDimension, - logger: this.logger - })); + const driver$ = Rx.of( + new HeadlessChromiumDriver(page, { + maxScreenshotDimension: this.browserConfig.maxScreenshotDimension, + logger: this.logger, + }) + ); const processError$ = Rx.fromEvent(page, 'error').pipe( - mergeMap((err) => Rx.throwError(new Error(`Unable to spawn Chromium: ${err}`))), + mergeMap(err => Rx.throwError(new Error(`Unable to spawn Chromium: [${err}]`))) ); const processPageError$ = Rx.fromEvent(page, 'pageerror').pipe( - mergeMap((err) => Rx.throwError(new Error(`Uncaught exception within the page: ${err}`))), + mergeMap(err => Rx.throwError(new Error(`Uncaught exception within the page: [${err}]`))) ); const processRequestFailed$ = Rx.fromEvent(page, 'requestfailed').pipe( - mergeMap((err) => Rx.throwError(new Error(`Request failed: ${err}`))), + mergeMap(req => { + const failure = req.failure && req.failure(); + if (failure) { + return Rx.throwError( + new Error(`Request to [${req.url()}] failed! [${failure.errorText}]`) + ); + } + return Rx.throwError(new Error(`Unknown failure! [${JSON.stringify(req)}]`)); + }) ); const processExit$ = Rx.fromEvent(browser, 'disconnected').pipe( - mergeMap((code) => Rx.throwError(new Error(`Chromium exited with: [${JSON.stringify({ code })}]`))) + mergeMap(code => + Rx.throwError(new Error(`Chromium exited with: [${JSON.stringify({ code })}]`)) + ) ); const nssError$ = message$.pipe( @@ -132,16 +149,26 @@ export class HeadlessChromiumDriverFactory { ); const fontError$ = message$.pipe( - filter(line => line.includes('Check failed: InitDefaultFont(). Could not find the default font')), - mergeMap(() => Rx.throwError(new Error('You must install freetype and ttf-font for Reporting to work'))) + filter(line => + line.includes('Check failed: InitDefaultFont(). Could not find the default font') + ), + mergeMap(() => + Rx.throwError(new Error('You must install freetype and ttf-font for Reporting to work')) + ) ); const noUsableSandbox$ = message$.pipe( filter(line => line.includes('No usable sandbox! Update your kernel')), - mergeMap(() => Rx.throwError(new Error(compactWhitespace(` + mergeMap(() => + Rx.throwError( + new Error( + compactWhitespace(` Unable to use Chromium sandbox. This can be disabled at your own risk with 'xpack.reporting.capture.browser.chromium.disableSandbox' - `)))) + `) + ) + ) + ) ); const exit$ = Rx.merge( @@ -158,17 +185,19 @@ export class HeadlessChromiumDriverFactory { driver$, consoleMessage$, message$, - exit$ + exit$, }); // unsubscribe logic makes a best-effort attempt to delete the user data directory used by chromium return () => { - this.logger.debug(`deleting chromium user data directory at ${userDataDir}`); + this.logger.debug(`deleting chromium user data directory at [${userDataDir}]`); // the unsubscribe function isn't `async` so we're going to make our best effort at // deleting the userDataDir and if it fails log an error. - rimraf(userDataDir, (err) => { + rimraf(userDataDir, err => { if (err) { - return this.logger.error(`error deleting user data directory at ${userDataDir}: ${err}`); + return this.logger.error( + `error deleting user data directory at [${userDataDir}]: [${err}]` + ); } }); }; diff --git a/x-pack/plugins/reporting/server/browsers/extract/extract.js b/x-pack/plugins/reporting/server/browsers/extract/extract.js index 92233cdd9ddfd..b205a8780349a 100644 --- a/x-pack/plugins/reporting/server/browsers/extract/extract.js +++ b/x-pack/plugins/reporting/server/browsers/extract/extract.js @@ -25,4 +25,4 @@ export async function extract(archivePath, targetPath) { } await unpacker(archivePath, targetPath); -} \ No newline at end of file +} diff --git a/x-pack/plugins/reporting/server/lib/create_queue.js b/x-pack/plugins/reporting/server/lib/create_queue.js index c09220a52c237..ceabfd74b2e09 100644 --- a/x-pack/plugins/reporting/server/lib/create_queue.js +++ b/x-pack/plugins/reporting/server/lib/create_queue.js @@ -6,7 +6,6 @@ import { Esqueue } from './esqueue'; import { createWorkersFactory } from './create_workers'; -import { QUEUE_DOCTYPE } from '../../common/constants'; import { oncePerServer } from './once_per_server'; import { createTaggedLogger } from './create_tagged_logger'; @@ -16,15 +15,13 @@ function createQueueFn(server) { const queueConfig = server.config().get('xpack.reporting.queue'); const index = server.config().get('xpack.reporting.index'); const createWorkers = createWorkersFactory(server); - const { getClient } = server.plugins.elasticsearch.getCluster('admin'); const logger = createTaggedLogger(server, ['reporting', 'esqueue']); const queueOptions = { - doctype: QUEUE_DOCTYPE, interval: queueConfig.indexInterval, timeout: queueConfig.timeout, dateSeparator: dateSeparator, - client: getClient(), + client: server.plugins.elasticsearch.getCluster('admin'), logger, }; diff --git a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/fixtures/elasticsearch.js b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/fixtures/elasticsearch.js index 70cb912c8f721..aec8641de9244 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/fixtures/elasticsearch.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/fixtures/elasticsearch.js @@ -3,105 +3,104 @@ import elasticsearch from 'elasticsearch'; import { constants } from '../../constants'; export function ClientMock() { - this.indices = { - create: () => Promise.resolve({ acknowledged: true }), - exists: () => Promise.resolve(false), - refresh: () => Promise.resolve(), - }; + this.callWithInternalUser = (endpoint, params = {}, ...rest) => { + if (endpoint === 'indices.create') { + return Promise.resolve({ acknowledged: true }); + } - this.transport = {}; -} + if (endpoint === 'indices.exists') { + return Promise.resolve(false); + } -ClientMock.prototype.index = function (params = {}) { - const shardCount = 2; - return Promise.resolve({ - _index: params.index || 'index', - _type: params.type || constants.DEFAULT_SETTING_DOCTYPE, - _id: params.id || uniqueId('testDoc'), - _seq_no: 1, - _primary_term: 1, - _shards: { total: shardCount, successful: shardCount, failed: 0 }, - created: true - }); -}; + if (endpoint === 'index') { + const shardCount = 2; + return Promise.resolve({ + _index: params.index || 'index', + _id: params.id || uniqueId('testDoc'), + _seq_no: 1, + _primary_term: 1, + _shards: { total: shardCount, successful: shardCount, failed: 0 }, + created: true + }); + } -ClientMock.prototype.ping = function () { - return Promise.resolve(); -}; + if (endpoint === 'get') { + if (params === elasticsearch.errors.NotFound) return elasticsearch.errors.NotFound; -ClientMock.prototype.get = function (params = {}, source = {}) { - if (params === elasticsearch.errors.NotFound) return elasticsearch.errors.NotFound; + const _source = { + jobtype: 'jobtype', + created_by: false, - const _source = { - jobtype: 'jobtype', - created_by: false, + payload: { + id: 'sample-job-1', + now: 'Mon Apr 25 2016 14:13:04 GMT-0700 (MST)' + }, - payload: { - id: 'sample-job-1', - now: 'Mon Apr 25 2016 14:13:04 GMT-0700 (MST)' - }, + priority: 10, + timeout: 10000, + created_at: '2016-04-25T21:13:04.738Z', + attempts: 0, + max_attempts: 3, + status: 'pending', + ...(rest[0] || {}) + }; - priority: 10, - timeout: 10000, - created_at: '2016-04-25T21:13:04.738Z', - attempts: 0, - max_attempts: 3, - status: 'pending', - ...source - }; + return Promise.resolve({ + _index: params.index || 'index', + _id: params.id || 'AVRPRLnlp7Ur1SZXfT-T', + _seq_no: params._seq_no || 1, + _primary_term: params._primary_term || 1, + found: true, + _source: _source + }); + } - return Promise.resolve({ - _index: params.index || 'index', - _type: params.type || constants.DEFAULT_SETTING_DOCTYPE, - _id: params.id || 'AVRPRLnlp7Ur1SZXfT-T', - _seq_no: params._seq_no || 1, - _primary_term: params._primary_term || 1, - found: true, - _source: _source - }); -}; + if (endpoint === 'search') { + const [count = 5, source = {}] = rest; + const hits = times(count, () => { + return { + _index: params.index || 'index', + _id: uniqueId('documentId'), + _seq_no: random(1, 5), + _primar_term: random(1, 5), + _score: null, + _source: { + created_at: new Date().toString(), + number: random(0, count, true), + ...source + } + }; + }); + return Promise.resolve({ + took: random(0, 10), + timed_out: false, + _shards: { + total: 5, + successful: 5, + failed: 0 + }, + hits: { + total: count, + max_score: null, + hits: hits + } + }); + } -ClientMock.prototype.search = function (params = {}, count = 5, source = {}) { - const hits = times(count, () => { - return { - _index: params.index || 'index', - _type: params.type || constants.DEFAULT_SETTING_DOCTYPE, - _id: uniqueId('documentId'), - _seq_no: random(1, 5), - _primar_term: random(1, 5), - _score: null, - _source: { - created_at: new Date().toString(), - number: random(0, count, true), - ...source - } - }; - }); - return Promise.resolve({ - took: random(0, 10), - timed_out: false, - _shards: { - total: 5, - successful: 5, - failed: 0 - }, - hits: { - total: count, - max_score: null, - hits: hits + if (endpoint === 'update') { + const shardCount = 2; + return Promise.resolve({ + _index: params.index || 'index', + _id: params.id || uniqueId('testDoc'), + _seq_no: params.if_seq_no + 1 || 2, + _primary_term: params.if_primary_term + 1 || 2, + _shards: { total: shardCount, successful: shardCount, failed: 0 }, + created: true + }); } - }); -}; -ClientMock.prototype.update = function (params = {}) { - const shardCount = 2; - return Promise.resolve({ - _index: params.index || 'index', - _type: params.type || constants.DEFAULT_SETTING_DOCTYPE, - _id: params.id || uniqueId('testDoc'), - _seq_no: params.if_seq_no + 1 || 2, - _primary_term: params.if_primary_term + 1 || 2, - _shards: { total: shardCount, successful: shardCount, failed: 0 }, - created: true - }); -}; + return Promise.resolve(); + }; + + this.transport = {}; +} diff --git a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/helpers/create_client.js b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/helpers/create_client.js deleted file mode 100644 index b4c1dcfbc8981..0000000000000 --- a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/helpers/create_client.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from 'expect.js'; -import proxyquire from 'proxyquire'; -import { ClientMock } from '../fixtures/elasticsearch'; - -const { createClient, isClient } = proxyquire.noPreserveCache()('../../helpers/create_client', { - 'elasticsearch': { Client: ClientMock } -}); - -describe('Create client helper', function () { - it('should have a client', function () { - const options = { - host: 'http://localhost:9200' - }; - const client = createClient(options); - expect(isClient(client)).to.be.ok(); - }); - - it('should use passed in instance', function () { - const clientInstance = new ClientMock(); - const client = createClient(clientInstance); - expect(client).to.equal(clientInstance); - }); -}); diff --git a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/helpers/create_index.js b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/helpers/create_index.js index 698f7e1605aa7..533ba93735c4f 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/helpers/create_index.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/helpers/create_index.js @@ -18,7 +18,7 @@ describe('Create Index', function () { beforeEach(function () { client = new ClientMock(); - createSpy = sinon.spy(client.indices, 'create'); + createSpy = sinon.spy(client, 'callWithInternalUser').withArgs('indices.create'); }); it('should return true', function () { @@ -29,49 +29,26 @@ describe('Create Index', function () { .then((exists) => expect(exists).to.be(true)); }); - it('should create the index with type mappings and default settings', function () { + it('should create the index with mappings and default settings', function () { const indexName = 'test-index'; - const docType = constants.DEFAULT_SETTING_DOCTYPE; const settings = constants.DEFAULT_SETTING_INDEX_SETTINGS; const result = createIndex(client, indexName); return result .then(function () { - const payload = createSpy.getCall(0).args[0]; + const payload = createSpy.getCall(0).args[1]; sinon.assert.callCount(createSpy, 1); expect(payload).to.have.property('index', indexName); expect(payload).to.have.property('body'); expect(payload.body).to.have.property('settings'); expect(payload.body.settings).to.eql(settings); expect(payload.body).to.have.property('mappings'); - expect(payload.body.mappings).to.have.property(docType); - expect(payload.body.mappings[docType]).to.have.property('properties'); - }); - }); - - it('should accept a custom doctype', function () { - const indexName = 'test-index'; - const docType = 'my_type'; - const settings = constants.DEFAULT_SETTING_INDEX_SETTINGS; - const result = createIndex(client, indexName, docType); - - return result - .then(function () { - const payload = createSpy.getCall(0).args[0]; - sinon.assert.callCount(createSpy, 1); - expect(payload).to.have.property('index', indexName); - expect(payload).to.have.property('body'); - expect(payload.body).to.have.property('settings'); - expect(payload.body.settings).to.eql(settings); - expect(payload.body).to.have.property('mappings'); - expect(payload.body.mappings).to.have.property(docType); - expect(payload.body.mappings[docType]).to.have.property('properties'); + expect(payload.body.mappings).to.have.property('properties'); }); }); it('should create the index with custom settings', function () { const indexName = 'test-index'; - const docType = constants.DEFAULT_SETTING_DOCTYPE; const settings = { ...constants.DEFAULT_SETTING_INDEX_SETTINGS, auto_expand_replicas: false, @@ -79,19 +56,18 @@ describe('Create Index', function () { number_of_replicas: 1, format: '3000', }; - const result = createIndex(client, indexName, docType, settings); + const result = createIndex(client, indexName, settings); return result .then(function () { - const payload = createSpy.getCall(0).args[0]; + const payload = createSpy.getCall(0).args[1]; sinon.assert.callCount(createSpy, 1); expect(payload).to.have.property('index', indexName); expect(payload).to.have.property('body'); expect(payload.body).to.have.property('settings'); expect(payload.body.settings).to.eql(settings); expect(payload.body).to.have.property('mappings'); - expect(payload.body.mappings).to.have.property(docType); - expect(payload.body.mappings[docType]).to.have.property('properties'); + expect(payload.body.mappings).to.have.property('properties'); }); }); }); @@ -102,8 +78,10 @@ describe('Create Index', function () { beforeEach(function () { client = new ClientMock(); - sinon.stub(client.indices, 'exists').callsFake(() => Promise.resolve(true)); - createSpy = sinon.spy(client.indices, 'create'); + sinon.stub(client, 'callWithInternalUser') + .withArgs('indices.exists') + .callsFake(() => Promise.resolve(true)); + createSpy = client.callWithInternalUser.withArgs('indices.create'); }); it('should return true', function () { diff --git a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/index.js b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/index.js index b7fd8e856c6fa..ad2da19579387 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/index.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/index.js @@ -36,27 +36,11 @@ describe('Esqueue class', function () { const init = () => new Esqueue(); expect(init).to.throwException(/must.+specify.+index/i); }); - - it('should throw with an invalid host', function () { - const init = () => new Esqueue('esqueue', { - client: { host: 'nope://nope' } - }); - - expect(init).to.throwException(/invalid.+protocol/i); - }); - - it('should throw with invalid hosts', function () { - const init = () => new Esqueue('esqueue', { - client: { hosts: [{ host: 'localhost', protocol: 'nope' }] } - }); - - expect(init).to.throwException(/invalid.+protocol/i); - }); }); describe('Queue construction', function () { it('should ping the ES server', function () { - const pingSpy = sinon.spy(client, 'ping'); + const pingSpy = sinon.spy(client, 'callWithInternalUser').withArgs('ping'); new Esqueue('esqueue', { client }); sinon.assert.calledOnce(pingSpy); }); @@ -93,7 +77,6 @@ describe('Esqueue class', function () { const job = queue.addJob(jobType, payload); const options = job.getProp('options'); expect(options).to.have.property('timeout', constants.DEFAULT_SETTING_TIMEOUT); - expect(options).to.have.property('doctype', constants.DEFAULT_SETTING_DOCTYPE); }); it('should pass queue index settings', function () { @@ -149,14 +132,12 @@ describe('Esqueue class', function () { it('should pass worker options', function () { const workerOptions = { size: 12, - doctype: 'tests' }; queue = new Esqueue('esqueue', { client }); const worker = queue.registerWorker('type', noop, workerOptions); const options = worker.getProp('options'); expect(options.size).to.equal(workerOptions.size); - expect(options.doctype).to.equal(workerOptions.doctype); }); }); diff --git a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/job.js b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/job.js index 7aefcf861f687..15ef68c1cb834 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/job.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/job.js @@ -25,7 +25,7 @@ const defaultCreatedBy = false; function validateDoc(spy) { sinon.assert.callCount(spy, 1); const spyCall = spy.getCall(0); - return spyCall.args[0]; + return spyCall.args[1]; } describe('Job Class', function () { @@ -70,10 +70,11 @@ describe('Job Class', function () { }); describe('construction', function () { + let indexSpy; beforeEach(function () { type = 'type1'; payload = { id: '123' }; - sinon.spy(client, 'index'); + indexSpy = sinon.spy(client, 'callWithInternalUser').withArgs('index'); }); it('should create the target index', function () { @@ -83,16 +84,14 @@ describe('Job Class', function () { const args = createIndexMock.getCall(0).args; expect(args[0]).to.equal(client); expect(args[1]).to.equal(index); - expect(args[2]).to.equal(constants.DEFAULT_SETTING_DOCTYPE); }); }); it('should index the payload', function () { const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs).to.have.property('index', index); - expect(indexArgs).to.have.property('type', constants.DEFAULT_SETTING_DOCTYPE); expect(indexArgs).to.have.property('body'); expect(indexArgs.body).to.have.property('payload', payload); }); @@ -101,9 +100,8 @@ describe('Job Class', function () { it('should index the job type', function () { const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs).to.have.property('index', index); - expect(indexArgs).to.have.property('type', constants.DEFAULT_SETTING_DOCTYPE); expect(indexArgs).to.have.property('body'); expect(indexArgs.body).to.have.property('jobtype', type); }); @@ -112,19 +110,19 @@ describe('Job Class', function () { it('should set event creation time', function () { const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('created_at'); }); }); it('should refresh the index', function () { - const refreshSpy = sinon.spy(client.indices, 'refresh'); + const refreshSpy = client.callWithInternalUser.withArgs('indices.refresh'); const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { sinon.assert.calledOnce(refreshSpy); const spyCall = refreshSpy.getCall(0); - expect(spyCall.args[0]).to.have.property('index', index); + expect(spyCall.args[1]).to.have.property('index', index); }); }); @@ -134,7 +132,6 @@ describe('Job Class', function () { try { expect(jobDoc).to.have.property('id'); expect(jobDoc).to.have.property('index'); - expect(jobDoc).to.have.property('type'); expect(jobDoc).to.have.property('_seq_no'); expect(jobDoc).to.have.property('_primary_term'); done(); @@ -163,8 +160,10 @@ describe('Job Class', function () { it('should emit error on client index failure', function (done) { const errMsg = 'test document index failure'; - client.index.restore(); - sinon.stub(client, 'index').callsFake(() => Promise.reject(new Error(errMsg))); + client.callWithInternalUser.restore(); + sinon.stub(client, 'callWithInternalUser') + .withArgs('index') + .callsFake(() => Promise.reject(new Error(errMsg))); const job = new Job(mockQueue, index, type, payload); job.once(constants.EVENT_JOB_CREATE_ERROR, (err) => { @@ -206,16 +205,17 @@ describe('Job Class', function () { }); describe('default values', function () { + let indexSpy; beforeEach(function () { type = 'type1'; payload = { id: '123' }; - sinon.spy(client, 'index'); + indexSpy = sinon.spy(client, 'callWithInternalUser').withArgs('index'); }); it('should set attempt count to 0', function () { const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('attempts', 0); }); }); @@ -223,7 +223,7 @@ describe('Job Class', function () { it('should index default created_by value', function () { const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('created_by', defaultCreatedBy); }); }); @@ -232,7 +232,7 @@ describe('Job Class', function () { const now = new Date().getTime(); const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('process_expiration'); expect(indexArgs.body.process_expiration.getTime()).to.be.lessThan(now); }); @@ -241,7 +241,7 @@ describe('Job Class', function () { it('should set status as pending', function () { const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('status', constants.JOB_STATUS_PENDING); }); }); @@ -249,7 +249,7 @@ describe('Job Class', function () { it('should have a default priority of 10', function () { const job = new Job(mockQueue, index, type, payload, options); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('priority', defaultPriority); }); }); @@ -257,13 +257,14 @@ describe('Job Class', function () { it('should set a browser type', function () { const job = new Job(mockQueue, index, type, payload); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('browser_type'); }); }); }); describe('option passing', function () { + let indexSpy; beforeEach(function () { type = 'type1'; payload = { id: '123' }; @@ -274,7 +275,7 @@ describe('Job Class', function () { authorization: 'Basic cXdlcnR5' } }; - sinon.spy(client, 'index'); + indexSpy = sinon.spy(client, 'callWithInternalUser').withArgs('index'); }); it('should index the created_by value', function () { @@ -284,7 +285,7 @@ describe('Job Class', function () { ...options }); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('created_by', createdBy); }); }); @@ -292,7 +293,7 @@ describe('Job Class', function () { it('should index timeout value from options', function () { const job = new Job(mockQueue, index, type, payload, options); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('timeout', options.timeout); }); }); @@ -300,7 +301,7 @@ describe('Job Class', function () { it('should set max attempt count', function () { const job = new Job(mockQueue, index, type, payload, options); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('max_attempts', options.max_attempts); }); }); @@ -308,7 +309,7 @@ describe('Job Class', function () { it('should add headers to the request params', function () { const job = new Job(mockQueue, index, type, payload, options); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs).to.have.property('headers', options.headers); }); }); @@ -316,7 +317,7 @@ describe('Job Class', function () { it(`should use upper priority of ${maxPriority}`, function () { const job = new Job(mockQueue, index, type, payload, { priority: maxPriority * 2 }); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('priority', maxPriority); }); }); @@ -324,51 +325,12 @@ describe('Job Class', function () { it(`should use lower priority of ${minPriority}`, function () { const job = new Job(mockQueue, index, type, payload, { priority: minPriority * 2 }); return job.ready.then(() => { - const indexArgs = validateDoc(client.index); + const indexArgs = validateDoc(indexSpy); expect(indexArgs.body).to.have.property('priority', minPriority); }); }); }); - describe('custom client', function () { - let newClient; - let job; - - beforeEach(function () { - sinon.spy(client, 'index'); - - newClient = new ClientMock(); - sinon.spy(newClient, 'index'); - job = new Job(mockQueue, index, type, payload, { - client: newClient, - ...options - }); - }); - - it('should create the target index', function () { - return job.ready.then(() => { - sinon.assert.calledOnce(createIndexMock); - const args = createIndexMock.getCall(0).args; - expect(args[0]).to.equal(newClient); - expect(args[1]).to.equal(index); - expect(args[2]).to.equal(constants.DEFAULT_SETTING_DOCTYPE); - }); - }); - - it('should index the payload', function () { - return job.ready.then(() => { - sinon.assert.callCount(client.index, 0); - sinon.assert.callCount(newClient.index, 1); - - const newDoc = newClient.index.getCall(0).args[0]; - expect(newDoc).to.have.property('index', index); - expect(newDoc).to.have.property('type', constants.DEFAULT_SETTING_DOCTYPE); - expect(newDoc).to.have.property('body'); - expect(newDoc.body).to.have.property('payload', payload); - }); - }); - }); - describe('get method', function () { beforeEach(function () { type = 'type2'; @@ -382,7 +344,6 @@ describe('Job Class', function () { .then((doc) => { const jobDoc = job.document; // document should be resolved expect(doc).to.have.property('index', index); - expect(doc).to.have.property('type', jobDoc.type); expect(doc).to.have.property('id', jobDoc.id); expect(doc).to.have.property('_seq_no', jobDoc._seq_no); expect(doc).to.have.property('_primary_term', jobDoc._primary_term); @@ -401,9 +362,11 @@ describe('Job Class', function () { }; const job = new Job(mockQueue, index, type, payload, optionals); - return Promise.resolve(client.get({}, optionals)) + return Promise.resolve(client.callWithInternalUser('get', {}, optionals)) .then((doc) => { - sinon.stub(client, 'get').returns(Promise.resolve(doc)); + sinon.stub(client, 'callWithInternalUser') + .withArgs('get') + .returns(Promise.resolve(doc)); }) .then(() => { return job.get() @@ -433,7 +396,6 @@ describe('Job Class', function () { const doc = job.toJSON(); expect(doc).to.have.property('index', index); - expect(doc).to.have.property('type', constants.DEFAULT_SETTING_DOCTYPE); expect(doc).to.have.property('jobtype', type); expect(doc).to.have.property('created_by', defaultCreatedBy); expect(doc).to.have.property('timeout', options.timeout); diff --git a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/worker.js b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/worker.js index 634d17661be35..64a0a578288d4 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/__tests__/worker.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/__tests__/worker.js @@ -102,11 +102,9 @@ describe('Worker class', function () { worker = new Worker(mockQueue, jobtype, workerFn, defaultWorkerOptions); expect(worker).to.have.property('id'); expect(worker).to.have.property('queue', mockQueue); - expect(worker).to.have.property('client', client); expect(worker).to.have.property('jobtype', jobtype); expect(worker).to.have.property('workerFn', workerFn); expect(worker).to.have.property('checkSize'); - expect(worker).to.have.property('doctype'); }); it('should have a unique ID', function () { @@ -118,14 +116,6 @@ describe('Worker class', function () { expect(worker.id).to.not.equal(worker2.id); }); - - it('should use custom client', function () { - const newClient = new ClientMock(); - worker = new Worker(mockQueue, 'test', noop, { ...defaultWorkerOptions, client: newClient }); - expect(worker).to.have.property('queue', mockQueue); - expect(worker).to.have.property('client', newClient); - expect(worker.client).to.not.equal(client); - }); }); describe('event emitting', function () { @@ -281,15 +271,14 @@ describe('Worker class', function () { function getSearchParams(jobtype = 'test', params = {}) { worker = new Worker(mockQueue, jobtype, noop, { ...defaultWorkerOptions, ...params }); worker._getPendingJobs(); - return searchStub.firstCall.args[0]; + return searchStub.firstCall.args[1]; } describe('error handling', function () { - beforeEach(() => { - }); - it('should pass search errors', function (done) { - searchStub = sinon.stub(mockQueue.client, 'search').callsFake(() => Promise.reject()); + searchStub = sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('search') + .callsFake(() => Promise.reject()); worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); worker._getPendingJobs() .then(() => done(new Error('should not resolve'))) @@ -301,9 +290,9 @@ describe('Worker class', function () { describe('missing index', function () { it('should swallow error', function (done) { - searchStub = sinon.stub(mockQueue.client, 'search').callsFake(() => Promise.reject({ - status: 404 - })); + searchStub = sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('search') + .callsFake(() => Promise.reject({ status: 404 })); worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); worker._getPendingJobs() .then(() => { done(); }) @@ -311,9 +300,9 @@ describe('Worker class', function () { }); it('should return an empty array', function (done) { - searchStub = sinon.stub(mockQueue.client, 'search').callsFake(() => Promise.reject({ - status: 404 - })); + searchStub = sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('search') + .callsFake(() => Promise.reject({ status: 404 })); worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); worker._getPendingJobs() .then((res) => { @@ -330,30 +319,14 @@ describe('Worker class', function () { }); }); - - describe('query parameters', function () { - beforeEach(() => { - searchStub = sinon.stub(mockQueue.client, 'search').callsFake(() => Promise.resolve({ hits: { hits: [] } })); - }); - - it('should query by default doctype', function () { - const params = getSearchParams(); - expect(params).to.have.property('type', constants.DEFAULT_SETTING_DOCTYPE); - }); - - it('should query by custom doctype', function () { - const doctype = 'custom_test'; - const params = getSearchParams('type', { doctype }); - expect(params).to.have.property('type', doctype); - }); - }); - describe('query body', function () { const conditionPath = 'query.bool.filter.bool'; const jobtype = 'test_jobtype'; beforeEach(() => { - searchStub = sinon.stub(mockQueue.client, 'search').callsFake(() => Promise.resolve({ hits: { hits: [] } })); + searchStub = sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('search') + .callsFake(() => Promise.resolve({ hits: { hits: [] } })); anchorMoment = moment(anchor); clock = sinon.useFakeTimers(anchorMoment.valueOf()); }); @@ -433,11 +406,11 @@ describe('Worker class', function () { type: 'test', id: 12345, }; - return mockQueue.client.get(params) + return mockQueue.client.callWithInternalUser('get', params) .then((jobDoc) => { job = jobDoc; worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); - updateSpy = sinon.spy(mockQueue.client, 'update'); + updateSpy = sinon.spy(mockQueue.client, 'callWithInternalUser').withArgs('update'); }); }); @@ -447,9 +420,8 @@ describe('Worker class', function () { it('should use seqNo and primaryTerm on update', function () { worker._claimJob(job); - const query = updateSpy.firstCall.args[0]; + const query = updateSpy.firstCall.args[1]; expect(query).to.have.property('index', job._index); - expect(query).to.have.property('type', job._type); expect(query).to.have.property('id', job._id); expect(query).to.have.property('if_seq_no', job._seq_no); expect(query).to.have.property('if_primary_term', job._primary_term); @@ -457,19 +429,19 @@ describe('Worker class', function () { it('should increment the job attempts', function () { worker._claimJob(job); - const doc = updateSpy.firstCall.args[0].body.doc; + const doc = updateSpy.firstCall.args[1].body.doc; expect(doc).to.have.property('attempts', job._source.attempts + 1); }); it('should update the job status', function () { worker._claimJob(job); - const doc = updateSpy.firstCall.args[0].body.doc; + const doc = updateSpy.firstCall.args[1].body.doc; expect(doc).to.have.property('status', constants.JOB_STATUS_PROCESSING); }); it('should set job expiration time', function () { worker._claimJob(job); - const doc = updateSpy.firstCall.args[0].body.doc; + const doc = updateSpy.firstCall.args[1].body.doc; const expiration = anchorMoment.add(defaults.timeout).toISOString(); expect(doc).to.have.property('process_expiration', expiration); }); @@ -501,8 +473,10 @@ describe('Worker class', function () { }); it('should reject the promise on conflict errors', function () { - mockQueue.client.update.restore(); - sinon.stub(mockQueue.client, 'update').returns(Promise.reject({ statusCode: 409 })); + mockQueue.client.callWithInternalUser.restore(); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.reject({ statusCode: 409 })); return worker._claimJob(job) .catch(err => { expect(err).to.eql({ statusCode: 409 }); @@ -510,8 +484,10 @@ describe('Worker class', function () { }); it('should reject the promise on other errors', function () { - mockQueue.client.update.restore(); - sinon.stub(mockQueue.client, 'update').returns(Promise.reject({ statusCode: 401 })); + mockQueue.client.callWithInternalUser.restore(); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.reject({ statusCode: 401 })); return worker._claimJob(job) .catch(err => { expect(err).to.eql({ statusCode: 401 }); @@ -522,7 +498,6 @@ describe('Worker class', function () { describe('find a pending job to claim', function () { const getMockJobs = (status = 'pending') => ([{ _index: 'myIndex', - _type: 'test', _id: 12345, _seq_no: 3, _primary_term: 3, @@ -545,11 +520,13 @@ describe('Worker class', function () { }); afterEach(() => { - mockQueue.client.update.restore(); + mockQueue.client.callWithInternalUser.restore(); }); it('should emit for errors from claiming job', function (done) { - sinon.stub(mockQueue.client, 'update').returns(Promise.reject({ statusCode: 401 })); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.reject({ statusCode: 401 })); worker.once(constants.EVENT_WORKER_JOB_CLAIM_ERROR, function (err) { try { @@ -567,7 +544,9 @@ describe('Worker class', function () { }); it('should reject the promise if an error claiming the job', function () { - sinon.stub(mockQueue.client, 'update').returns(Promise.reject({ statusCode: 409 })); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.reject({ statusCode: 409 })); return worker._claimPendingJobs(getMockJobs()) .catch(err => { expect(err).to.eql({ statusCode: 409 }); @@ -575,12 +554,13 @@ describe('Worker class', function () { }); it('should get the pending job', function () { - sinon.stub(mockQueue.client, 'update').returns(Promise.resolve({ test: 'cool' })); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.resolve({ test: 'cool' })); sinon.stub(worker, '_performJob').callsFake(identity); return worker._claimPendingJobs(getMockJobs()) .then(claimedJob => { expect(claimedJob._index).to.be('myIndex'); - expect(claimedJob._type).to.be('test'); expect(claimedJob._source.jobtype).to.be('jobtype'); expect(claimedJob._source.status).to.be('processing'); expect(claimedJob.test).to.be('cool'); @@ -597,11 +577,11 @@ describe('Worker class', function () { anchorMoment = moment(anchor); clock = sinon.useFakeTimers(anchorMoment.valueOf()); - return mockQueue.client.get() + return mockQueue.client.callWithInternalUser('get') .then((jobDoc) => { job = jobDoc; worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); - updateSpy = sinon.spy(mockQueue.client, 'update'); + updateSpy = sinon.spy(mockQueue.client, 'callWithInternalUser').withArgs('update'); }); }); @@ -611,9 +591,8 @@ describe('Worker class', function () { it('should use _seq_no and _primary_term on update', function () { worker._failJob(job); - const query = updateSpy.firstCall.args[0]; + const query = updateSpy.firstCall.args[1]; expect(query).to.have.property('index', job._index); - expect(query).to.have.property('type', job._type); expect(query).to.have.property('id', job._id); expect(query).to.have.property('if_seq_no', job._seq_no); expect(query).to.have.property('if_primary_term', job._primary_term); @@ -621,28 +600,32 @@ describe('Worker class', function () { it('should set status to failed', function () { worker._failJob(job); - const doc = updateSpy.firstCall.args[0].body.doc; + const doc = updateSpy.firstCall.args[1].body.doc; expect(doc).to.have.property('status', constants.JOB_STATUS_FAILED); }); it('should append error message if supplied', function () { const msg = 'test message'; worker._failJob(job, msg); - const doc = updateSpy.firstCall.args[0].body.doc; + const doc = updateSpy.firstCall.args[1].body.doc; expect(doc).to.have.property('output'); expect(doc.output).to.have.property('content', msg); }); it('should return true on conflict errors', function () { - mockQueue.client.update.restore(); - sinon.stub(mockQueue.client, 'update').returns(Promise.reject({ statusCode: 409 })); + mockQueue.client.callWithInternalUser.restore(); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.reject({ statusCode: 409 })); return worker._failJob(job) .then((res) => expect(res).to.equal(true)); }); it('should return false on other document update errors', function () { - mockQueue.client.update.restore(); - sinon.stub(mockQueue.client, 'update').returns(Promise.reject({ statusCode: 401 })); + mockQueue.client.callWithInternalUser.restore(); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.reject({ statusCode: 401 })); return worker._failJob(job) .then((res) => expect(res).to.equal(false)); }); @@ -653,7 +636,7 @@ describe('Worker class', function () { clock.tick(100); worker._failJob(job, msg); - const doc = updateSpy.firstCall.args[0].body.doc; + const doc = updateSpy.firstCall.args[1].body.doc; expect(doc).to.have.property('output'); expect(doc).to.have.property('status', constants.JOB_STATUS_FAILED); expect(doc).to.have.property('completed_at'); @@ -677,8 +660,10 @@ describe('Worker class', function () { }); it('should emit on other document update errors', function (done) { - mockQueue.client.update.restore(); - sinon.stub(mockQueue.client, 'update').returns(Promise.reject({ statusCode: 401 })); + mockQueue.client.callWithInternalUser.restore(); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.reject({ statusCode: 401 })); worker.on(constants.EVENT_WORKER_FAIL_UPDATE_ERROR, function (err) { try { @@ -705,10 +690,10 @@ describe('Worker class', function () { value: random(0, 100, true) }; - return mockQueue.client.get({}, { payload }) + return mockQueue.client.callWithInternalUser('get', {}, { payload }) .then((jobDoc) => { job = jobDoc; - updateSpy = sinon.spy(mockQueue.client, 'update'); + updateSpy = sinon.spy(mockQueue.client, 'callWithInternalUser').withArgs('update'); }); }); @@ -733,9 +718,8 @@ describe('Worker class', function () { return worker._performJob(job) .then(() => { sinon.assert.calledOnce(updateSpy); - const query = updateSpy.firstCall.args[0]; + const query = updateSpy.firstCall.args[1]; expect(query).to.have.property('index', job._index); - expect(query).to.have.property('type', job._type); expect(query).to.have.property('id', job._id); expect(query).to.have.property('if_seq_no', job._seq_no); expect(query).to.have.property('if_primary_term', job._primary_term); @@ -758,7 +742,7 @@ describe('Worker class', function () { return worker._performJob(job) .then(() => { sinon.assert.calledOnce(updateSpy); - const doc = updateSpy.firstCall.args[0].body.doc; + const doc = updateSpy.firstCall.args[1].body.doc; expect(doc).to.have.property('status', constants.JOB_STATUS_COMPLETED); expect(doc).to.have.property('completed_at'); const completedTimestamp = moment(doc.completed_at).valueOf(); @@ -776,7 +760,6 @@ describe('Worker class', function () { expect(workerJob).to.have.property('job'); expect(workerJob.job).to.have.property('id'); expect(workerJob.job).to.have.property('index'); - expect(workerJob.job).to.have.property('type'); expect(workerJob).to.have.property('output'); expect(workerJob.output).to.have.property('content'); @@ -880,7 +863,9 @@ describe('Worker class', function () { } }; - sinon.stub(mockQueue.client, 'update').returns(Promise.reject({ statusCode: 413 })); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('update') + .returns(Promise.reject({ statusCode: 413 })); const workerFn = function (jobPayload) { return new Promise(function (resolve) { @@ -899,7 +884,9 @@ describe('Worker class', function () { describe('search failure', function () { it('causes _processPendingJobs to reject the Promise', function () { - sinon.stub(mockQueue.client, 'search').returns(Promise.reject(new Error('test error'))); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('search') + .returns(Promise.reject(new Error('test error'))); worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); return worker._processPendingJobs() .then(() => { @@ -998,7 +985,9 @@ describe('Worker class', function () { }; beforeEach(function () { - sinon.stub(mockQueue.client, 'search').callsFake(() => Promise.resolve({ hits: { hits: [] } })); + sinon.stub(mockQueue.client, 'callWithInternalUser') + .withArgs('search') + .callsFake(() => Promise.resolve({ hits: { hits: [] } })); }); describe('workerFn rejects promise', function () { diff --git a/x-pack/plugins/reporting/server/lib/esqueue/constants/default_settings.js b/x-pack/plugins/reporting/server/lib/esqueue/constants/default_settings.js index 539ece36e6e6d..5df580a063dd9 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/constants/default_settings.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/constants/default_settings.js @@ -8,7 +8,6 @@ export const defaultSettings = { DEFAULT_SETTING_TIMEOUT: 10000, DEFAULT_SETTING_DATE_SEPARATOR: '-', DEFAULT_SETTING_INTERVAL: 'week', - DEFAULT_SETTING_DOCTYPE: 'esqueue', DEFAULT_SETTING_INDEX_SETTINGS: { number_of_shards: 1, auto_expand_replicas: '0-1', diff --git a/x-pack/plugins/reporting/server/lib/esqueue/helpers/create_client.js b/x-pack/plugins/reporting/server/lib/esqueue/helpers/create_client.js deleted file mode 100644 index 184b268c66598..0000000000000 --- a/x-pack/plugins/reporting/server/lib/esqueue/helpers/create_client.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import elasticsearch from 'elasticsearch'; - -export function createClient(options) { - let client; - - if (isClient(options)) { - client = options; - } else { - client = new elasticsearch.Client(options); - } - - return client; -} - -export function isClient(client) { - // if there's a transport property, assume it's a client instance - return !!client.transport; -} diff --git a/x-pack/plugins/reporting/server/lib/esqueue/helpers/create_index.js b/x-pack/plugins/reporting/server/lib/esqueue/helpers/create_index.js index 012b2d1ff54ac..568b6b6c70ae2 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/helpers/create_index.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/helpers/create_index.js @@ -66,29 +66,24 @@ const schema = { } }; -export function createIndex(client, indexName, - doctype = constants.DEFAULT_SETTING_DOCTYPE, - indexSettings = { }) { +export function createIndex(client, indexName, indexSettings = {}) { const body = { settings: { ...constants.DEFAULT_SETTING_INDEX_SETTINGS, ...indexSettings }, mappings: { - [doctype]: { - properties: schema - } + properties: schema } }; - return client.indices.exists({ + return client.callWithInternalUser('indices.exists', { index: indexName, }) .then((exists) => { if (!exists) { - return client.indices.create({ + return client.callWithInternalUser('indices.create', { index: indexName, - include_type_name: true, body: body }) .then(() => true) diff --git a/x-pack/plugins/reporting/server/lib/esqueue/index.js b/x-pack/plugins/reporting/server/lib/esqueue/index.js index ce07ba00bae1c..5a5ef21843e3a 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/index.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/index.js @@ -8,7 +8,6 @@ import { EventEmitter } from 'events'; import { Job } from './job'; import { Worker } from './worker'; import { constants } from './constants'; -import { createClient } from './helpers/create_client'; import { indexTimestamp } from './helpers/index_timestamp'; import { omit } from 'lodash'; @@ -23,11 +22,10 @@ export class Esqueue extends EventEmitter { this.settings = { interval: constants.DEFAULT_SETTING_INTERVAL, timeout: constants.DEFAULT_SETTING_TIMEOUT, - doctype: constants.DEFAULT_SETTING_DOCTYPE, dateSeparator: constants.DEFAULT_SETTING_DATE_SEPARATOR, ...omit(options, [ 'client' ]) }; - this.client = createClient(options.client || {}); + this.client = options.client; this._logger = options.logger || function () {}; this._workers = []; this._initTasks().catch((err) => this.emit(constants.EVENT_QUEUE_ERROR, err)); @@ -35,7 +33,7 @@ export class Esqueue extends EventEmitter { _initTasks() { const initTasks = [ - this.client.ping(), + this.client.callWithInternalUser('ping'), ]; return Promise.all(initTasks).catch((err) => { @@ -44,7 +42,7 @@ export class Esqueue extends EventEmitter { }); } - addJob(type, payload, opts = {}) { + addJob(jobtype, payload, opts = {}) { const timestamp = indexTimestamp(this.settings.interval, this.settings.dateSeparator); const index = `${this.index}-${timestamp}`; const defaults = { @@ -52,12 +50,11 @@ export class Esqueue extends EventEmitter { }; const options = Object.assign(defaults, opts, { - doctype: this.settings.doctype, indexSettings: this.settings.indexSettings, logger: this._logger }); - return new Job(this, index, type, payload, options); + return new Job(this, index, jobtype, payload, options); } registerWorker(type, workerFn, opts) { diff --git a/x-pack/plugins/reporting/server/lib/esqueue/job.js b/x-pack/plugins/reporting/server/lib/esqueue/job.js index 097178a160626..053620932d5c5 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/job.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/job.js @@ -13,23 +13,22 @@ import { isPlainObject } from 'lodash'; const puid = new Puid(); export class Job extends events.EventEmitter { - constructor(queue, index, type, payload, options = {}) { - if (typeof type !== 'string') throw new Error('Type must be a string'); + constructor(queue, index, jobtype, payload, options = {}) { + if (typeof jobtype !== 'string') throw new Error('Jobtype must be a string'); if (!isPlainObject(payload)) throw new Error('Payload must be a plain object'); super(); this.queue = queue; - this.client = options.client || this.queue.client; + this._client = this.queue.client; this.id = puid.generate(); this.index = index; - this.jobtype = type; + this.jobtype = jobtype; this.payload = payload; this.created_by = options.created_by || false; this.timeout = options.timeout || 10000; this.maxAttempts = options.max_attempts || 3; this.priority = Math.max(Math.min(options.priority || 10, 20), -20); - this.doctype = options.doctype || constants.DEFAULT_SETTING_DOCTYPE; this.indexSettings = options.indexSettings || {}; this.browser_type = options.browser_type; @@ -48,7 +47,6 @@ export class Job extends events.EventEmitter { const indexParams = { index: this.index, - type: this.doctype, id: this.id, body: { jobtype: this.jobtype, @@ -75,19 +73,18 @@ export class Job extends events.EventEmitter { indexParams.headers = options.headers; } - this.ready = createIndex(this.client, this.index, this.doctype, this.indexSettings) - .then(() => this.client.index(indexParams)) + this.ready = createIndex(this._client, this.index, this.indexSettings) + .then(() => this._client.callWithInternalUser('index', indexParams)) .then((doc) => { this.document = { id: doc._id, - type: doc._type, index: doc._index, _seq_no: doc._seq_no, _primary_term: doc._primary_term, }; this.debug(`Job created in index ${this.index}`); - return this.client.indices.refresh({ + return this._client.callWithInternalUser('indices.refresh', { index: this.index }).then(() => { this.debug(`Job index refreshed ${this.index}`); @@ -108,9 +105,8 @@ export class Job extends events.EventEmitter { get() { return this.ready .then(() => { - return this.client.get({ + return this._client.callWithInternalUser('get', { index: this.index, - type: this.doctype, id: this.id }); }) @@ -118,7 +114,6 @@ export class Job extends events.EventEmitter { return Object.assign(doc._source, { index: doc._index, id: doc._id, - type: doc._type, _seq_no: doc._seq_no, _primary_term: doc._primary_term, }); @@ -129,7 +124,6 @@ export class Job extends events.EventEmitter { return { id: this.id, index: this.index, - type: this.doctype, jobtype: this.jobtype, created_by: this.created_by, payload: this.payload, diff --git a/x-pack/plugins/reporting/server/lib/esqueue/worker.js b/x-pack/plugins/reporting/server/lib/esqueue/worker.js index 383f4cfb47e92..8c3c8ae610c4c 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/worker.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/worker.js @@ -17,7 +17,6 @@ const puid = new Puid(); function formatJobObject(job) { return { index: job._index, - type: job._type, id: job._id, }; } @@ -52,11 +51,10 @@ export class Worker extends events.EventEmitter { this.kibanaId = opts.kibanaId; this.kibanaName = opts.kibanaName; this.queue = queue; - this.client = opts.client || this.queue.client; + this._client = this.queue.client; this.jobtype = type; this.workerFn = workerFn; this.checkSize = opts.size || 10; - this.doctype = opts.doctype || constants.DEFAULT_SETTING_DOCTYPE; this.debug = getLogger(opts, this.id, 'debug'); this.warn = getLogger(opts, this.id, 'warn'); @@ -86,7 +84,6 @@ export class Worker extends events.EventEmitter { id: this.id, index: this.queue.index, jobType: this.jobType, - doctype: this.doctype, }; } @@ -126,9 +123,8 @@ export class Worker extends events.EventEmitter { kibana_name: this.kibanaName, }; - return this.client.update({ + return this._client.callWithInternalUser('update', { index: job._index, - type: job._type, id: job._id, if_seq_no: job._seq_no, if_primary_term: job._primary_term, @@ -164,9 +160,8 @@ export class Worker extends events.EventEmitter { output: docOutput, }); - return this.client.update({ + return this._client.callWithInternalUser('update', { index: job._index, - type: job._type, id: job._id, if_seq_no: job._seq_no, if_primary_term: job._primary_term, @@ -242,9 +237,8 @@ export class Worker extends events.EventEmitter { output: docOutput }; - return this.client.update({ + return this._client.callWithInternalUser('update', { index: job._index, - type: job._type, id: job._id, if_seq_no: job._seq_no, if_primary_term: job._primary_term, @@ -386,9 +380,8 @@ export class Worker extends events.EventEmitter { size: this.checkSize }; - return this.client.search({ + return this._client.callWithInternalUser('search', { index: `${this.queue.index}-*`, - type: this.doctype, body: query }) .then((results) => { diff --git a/x-pack/plugins/reporting/server/lib/jobs_query.js b/x-pack/plugins/reporting/server/lib/jobs_query.js index 11af14968198d..e4f501e2c9518 100644 --- a/x-pack/plugins/reporting/server/lib/jobs_query.js +++ b/x-pack/plugins/reporting/server/lib/jobs_query.js @@ -5,7 +5,6 @@ */ import { get } from 'lodash'; -import { QUEUE_DOCTYPE } from '../../common/constants'; import { oncePerServer } from './once_per_server'; const defaultSize = 10; @@ -18,7 +17,7 @@ function jobsQueryFn(server) { return get(user, 'username', false); } - function execQuery(type, body) { + function execQuery(queryType, body) { const defaultBody = { search: { _source: { @@ -33,11 +32,10 @@ function jobsQueryFn(server) { const query = { index: `${index}-*`, - type: QUEUE_DOCTYPE, - body: Object.assign(defaultBody[type] || {}, body) + body: Object.assign(defaultBody[queryType] || {}, body) }; - return callWithInternalUser(type, query) + return callWithInternalUser(queryType, query) .catch((err) => { if (err instanceof esErrors['401']) return; if (err instanceof esErrors['403']) return; @@ -73,7 +71,7 @@ function jobsQueryFn(server) { if (jobIds) { body.query.constant_score.filter.bool.must.push({ - ids: { type: QUEUE_DOCTYPE, values: jobIds } + ids: { values: jobIds } }); } diff --git a/x-pack/plugins/rollup/index.js b/x-pack/plugins/rollup/index.js index 02095c97d9379..663cc92f38c32 100644 --- a/x-pack/plugins/rollup/index.js +++ b/x-pack/plugins/rollup/index.js @@ -8,6 +8,7 @@ import { resolve } from 'path'; import { PLUGIN } from './common'; import { registerLicenseChecker } from './server/lib/register_license_checker'; import { rollupDataEnricher } from './rollup_data_enricher'; +import { registerRollupSearchStrategy } from './server/lib/search_strategies'; import { registerIndicesRoute, registerFieldsForWildcardRoute, @@ -52,6 +53,8 @@ export function rollup(kibana) { ) { server.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); } + + registerRollupSearchStrategy(this.kbnServer, server); } }); } diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js index 4372388d017f4..bee32a44c35a0 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js @@ -27,4 +27,4 @@ export const TabJson = ({ }} /> ); -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js index 487f70c55428a..e631a7b6c0877 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js @@ -6,8 +6,7 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; - -import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices'; +import { findIllegalCharactersInIndexName } from 'ui/indices'; export function validateRollupIndex(rollupIndex, indexPattern) { if (!rollupIndex || !rollupIndex.trim()) { @@ -28,13 +27,7 @@ export function validateRollupIndex(rollupIndex, indexPattern) { )]; } - const illegalCharacters = INDEX_ILLEGAL_CHARACTERS_VISIBLE.reduce((chars, char) => { - if (rollupIndex.includes(char)) { - chars.push(char); - } - - return chars; - }, []); + const illegalCharacters = findIllegalCharactersInIndexName(rollupIndex); if (illegalCharacters.length) { return [( diff --git a/x-pack/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js b/x-pack/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js index 41f575af2c2d2..c68509cad6de2 100644 --- a/x-pack/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js +++ b/x-pack/plugins/rollup/server/lib/call_with_request_factory/call_with_request_factory.js @@ -8,10 +8,7 @@ import { once } from 'lodash'; import { elasticsearchJsPlugin } from '../../client/elasticsearch_rollup'; const callWithRequest = once((server) => { - const config = { - plugins: [ elasticsearchJsPlugin ], - ...server.config().get('elasticsearch') - }; + const config = { plugins: [ elasticsearchJsPlugin ] }; const cluster = server.plugins.elasticsearch.createCluster('rollup', config); return cluster.callWithRequest; diff --git a/x-pack/plugins/rollup/server/lib/license_pre_routing_factory/index.js b/x-pack/plugins/rollup/server/lib/license_pre_routing_factory/index.js index a6903bcf11a78..0743e443955f4 100644 --- a/x-pack/plugins/rollup/server/lib/license_pre_routing_factory/index.js +++ b/x-pack/plugins/rollup/server/lib/license_pre_routing_factory/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { licensePreRoutingFactory } from './license_pre_routing_factory'; \ No newline at end of file +export { licensePreRoutingFactory } from './license_pre_routing_factory'; diff --git a/x-pack/plugins/rollup/server/lib/merge_capabilities_with_fields.js b/x-pack/plugins/rollup/server/lib/merge_capabilities_with_fields.js new file mode 100644 index 0000000000000..bbad5d9e4e48e --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/merge_capabilities_with_fields.js @@ -0,0 +1,67 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ + +// Merge rollup capabilities information with field information + +export const mergeCapabilitiesWithFields = (rollupIndexCapabilities, fieldsFromFieldCapsApi, previousFields = []) => { + const rollupFields = [...previousFields]; + const rollupFieldNames = []; + + Object.keys(rollupIndexCapabilities).forEach(agg => { + + // Field names of the aggregation + const fields = Object.keys(rollupIndexCapabilities[agg]); + + // Default field information + const defaultField = { + name: null, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }; + + // Date histogram agg only ever has one field defined, let date type overwrite a + // previous type if defined (such as number from max and min aggs). + if(agg === 'date_histogram') { + const timeFieldName = fields[0]; + const fieldCapsKey = `${timeFieldName}.${agg}.timestamp`; + const newField = { + ...fieldsFromFieldCapsApi[fieldCapsKey], + ...defaultField, + name: timeFieldName, + }; + const existingField = rollupFields.find(field => field.name === timeFieldName); + + if(existingField) { + Object.assign(existingField, newField); + } else { + rollupFieldNames.push(timeFieldName); + rollupFields.push(newField); + } + } + // For all other aggs, filter out ones that have already been added to the field list + // because the same field can be part of multiple aggregations, but end consumption + // doesn't differentiate fields based on their aggregation abilities. + else { + rollupFields.push( + ...fields + .filter(field => !rollupFieldNames.includes(field)) + .map(field => { + // Expand each field into object format that end consumption expects. + const fieldCapsKey = `${field}.${agg}.value`; + rollupFieldNames.push(field); + return { + ...fieldsFromFieldCapsApi[fieldCapsKey], + ...defaultField, + name: field, + }; + }) + ); + } + }); + + return rollupFields; +}; diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/index.js b/x-pack/plugins/rollup/server/lib/search_strategies/index.js new file mode 100644 index 0000000000000..2d2711dfc932f --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/index.js @@ -0,0 +1,7 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ + +export { registerRollupSearchStrategy } from './register_rollup_search_strategy'; diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js b/x-pack/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js new file mode 100644 index 0000000000000..a7efed9850fc2 --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.js @@ -0,0 +1,27 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ +import { getRollupSearchStrategy } from './rollup_search_strategy'; +import { getRollupSearchRequest } from './rollup_search_request'; +import { getRollupSearchCapabilities } from './rollup_search_capabilities'; + +export const registerRollupSearchStrategy = (kbnServer, server) => kbnServer.afterPluginsInit(() => { + if (!server.plugins.metrics) { + return; + } + + const { + addSearchStrategy, + AbstractSearchRequest, + AbstractSearchStrategy, + DefaultSearchCapabilities, + } = server.plugins.metrics; + + const RollupSearchRequest = getRollupSearchRequest(AbstractSearchRequest); + const RollupSearchCapabilities = getRollupSearchCapabilities(DefaultSearchCapabilities); + const RollupSearchStrategy = getRollupSearchStrategy(AbstractSearchStrategy, RollupSearchRequest, RollupSearchCapabilities); + + addSearchStrategy(new RollupSearchStrategy(server)); +}); diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js b/x-pack/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js new file mode 100644 index 0000000000000..acd2d48c89706 --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/register_rollup_search_strategy.test.js @@ -0,0 +1,52 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ +import { registerRollupSearchStrategy } from './register_rollup_search_strategy'; + +describe('Register Rollup Search Strategy', () => { + let kbnServer; + let metrics; + + beforeEach(() => { + const afterPluginsInit = jest.fn((callback) => callback()); + + kbnServer = { + afterPluginsInit, + }; + + metrics = { + addSearchStrategy: jest.fn().mockName('addSearchStrategy'), + AbstractSearchRequest: jest.fn().mockName('AbstractSearchRequest'), + AbstractSearchStrategy: jest.fn().mockName('AbstractSearchStrategy'), + DefaultSearchCapabilities: jest.fn().mockName('DefaultSearchCapabilities'), + }; + }); + + test('should run initialization on "afterPluginsInit" hook', () => { + registerRollupSearchStrategy(kbnServer, { + plugins: {}, + }); + + expect(kbnServer.afterPluginsInit).toHaveBeenCalled(); + }); + + test('should run initialization if metrics plugin available', () => { + registerRollupSearchStrategy(kbnServer, { + plugins: { + metrics, + }, + }); + + expect(metrics.addSearchStrategy).toHaveBeenCalled(); + }); + + test('should not run initialization if metrics plugin unavailable', () => { + registerRollupSearchStrategy(kbnServer, { + plugins: {}, + }); + + expect(metrics.addSearchStrategy).not.toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.js b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.js new file mode 100644 index 0000000000000..3e26b5c9b8532 --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.js @@ -0,0 +1,53 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ +import { get } from 'lodash'; +import { unitsMap } from '@elastic/datemath'; + +const leastCommonInterval = (num = 0, base = 0) => Math.max(Math.ceil(num / base) * base, base); + +const getDateHistogramAggregation = (fieldsCapabilities, rollupIndex) => { + const dateHistogramField = fieldsCapabilities[rollupIndex].aggs.date_histogram; + + // there is also only one valid date_histogram field + return Object.values(dateHistogramField)[0]; +}; + +const isCalendarInterval = ({ unit, value }) => value === 1 && ['calendar', 'mixed'].includes(unitsMap[unit].type); + +export const getRollupSearchCapabilities = (DefaultSearchCapabilities) => + (class RollupSearchCapabilities extends DefaultSearchCapabilities { + constructor(req, batchRequestsSupport, fieldsCapabilities, rollupIndex) { + super(req, batchRequestsSupport, fieldsCapabilities); + + this.rollupIndex = rollupIndex; + this.dateHistogram = getDateHistogramAggregation(fieldsCapabilities, rollupIndex); + } + + get defaultTimeInterval() { + return get(this.dateHistogram, 'interval', null); + } + + get searchTimezone() { + return get(this.dateHistogram, 'time_zone', null); + } + + getValidTimeInterval(userIntervalString) { + const parsedRollupJobInterval = this.parseInterval(this.defaultTimeInterval); + const parsedUserInterval = this.parseInterval(userIntervalString); + + let { unit } = parsedRollupJobInterval; + let { value } = this.convertIntervalToUnit(userIntervalString, unit); + + if (isCalendarInterval(parsedRollupJobInterval) && isCalendarInterval(parsedUserInterval)) { + unit = value > 1 ? parsedUserInterval.unit : parsedRollupJobInterval.unit; + value = 1; + } else { + value = leastCommonInterval(value, parsedRollupJobInterval.value); + } + + return `${value}${unit}`; + } + }); diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.test.js b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.test.js new file mode 100644 index 0000000000000..39906783fa1fa --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_capabilities.test.js @@ -0,0 +1,147 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ +import { getRollupSearchCapabilities } from './rollup_search_capabilities'; + +class DefaultSearchCapabilities { + constructor(request, batchRequestsSupport, fieldsCapabilities = {}) { + this.fieldsCapabilities = fieldsCapabilities; + this.parseInterval = jest.fn((interval) => interval); + } +} + +describe('Rollup Search Capabilities', () => { + const testTimeZone = 'time_zone'; + const testInterval = '10s'; + const rollupIndex = 'rollupIndex'; + const batchRequestsSupport = true; + const request = {}; + + let RollupSearchCapabilities; + let fieldsCapabilities; + let rollupSearchCaps; + + beforeEach(() => { + RollupSearchCapabilities = getRollupSearchCapabilities(DefaultSearchCapabilities); + fieldsCapabilities = { + [rollupIndex]: { + aggs: { + date_histogram: { + histogram_field: { + time_zone: testTimeZone, + interval: testInterval, + }, + }, + }, + }, + }; + + rollupSearchCaps = new RollupSearchCapabilities(request, batchRequestsSupport, fieldsCapabilities, rollupIndex); + }); + + test('should create instance of RollupSearchRequest', () => { + expect(rollupSearchCaps).toBeInstanceOf(DefaultSearchCapabilities); + expect(rollupSearchCaps.fieldsCapabilities).toBe(fieldsCapabilities); + expect(rollupSearchCaps.rollupIndex).toBe(rollupIndex); + }); + + test('should return the "timezone" for the rollup request', () => { + expect(rollupSearchCaps.searchTimezone).toBe(testTimeZone); + }); + + test('should return the default "interval" for the rollup request', () => { + expect(rollupSearchCaps.defaultTimeInterval).toBe(testInterval); + }); + + describe('getValidTimeInterval', () => { + let parsedDefaultInterval; + let parsedUserIntervalString; + let convertedIntervalIntoDefaultUnit; + + beforeEach(() => { + convertedIntervalIntoDefaultUnit = null; + + rollupSearchCaps.parseInterval = jest.fn() + .mockImplementationOnce(() => parsedDefaultInterval) + .mockImplementationOnce(() => parsedUserIntervalString); + rollupSearchCaps.convertIntervalToUnit = jest + .fn(() => convertedIntervalIntoDefaultUnit || parsedUserIntervalString); + }); + + test('should return 1w as common interval for 1w(user interval) and 1d(rollup interval) - calendar intervals', () => { + parsedDefaultInterval = { + value: 1, + unit: 'd', + }; + parsedUserIntervalString = { + value: 1, + unit: 'w', + }; + convertedIntervalIntoDefaultUnit = { + value: 7, + unit: 'd', + }; + + expect(rollupSearchCaps.getValidTimeInterval()).toBe('1w'); + }); + + test('should return 1w as common interval for 1d(user interval) and 1w(rollup interval) - calendar intervals', () => { + parsedDefaultInterval = { + value: 1, + unit: 'w', + }; + parsedUserIntervalString = { + value: 1, + unit: 'd', + }; + convertedIntervalIntoDefaultUnit = { + value: 1 / 7, + unit: 'w', + }; + + expect(rollupSearchCaps.getValidTimeInterval()).toBe('1w'); + }); + + test('should return 2y as common interval for 0.1y(user interval) and 2y(rollup interval) - fixed intervals', () => { + parsedDefaultInterval = { + value: 2, + unit: 'y', + }; + parsedUserIntervalString = { + value: 0.1, + unit: 'y', + }; + + expect(rollupSearchCaps.getValidTimeInterval()).toBe('2y'); + }); + + test('should return 3h as common interval for 2h(user interval) and 3h(rollup interval) - fixed intervals', () => { + parsedDefaultInterval = { + value: 3, + unit: 'h', + }; + parsedUserIntervalString = { + value: 2, + unit: 'h', + }; + + expect(rollupSearchCaps.getValidTimeInterval()).toBe('3h'); + }); + + test('should return 6m as common interval for 4m(user interval) and 3m(rollup interval) - fixed intervals', () => { + parsedDefaultInterval = { + value: 3, + unit: 'm', + }; + parsedUserIntervalString = { + value: 4, + unit: 'm', + }; + + expect(rollupSearchCaps.getValidTimeInterval()).toBe('6m'); + }); + }); + +}); diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_request.js b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_request.js new file mode 100644 index 0000000000000..6ec8d9a882168 --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_request.js @@ -0,0 +1,21 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ +const SEARCH_METHOD = 'rollup.search'; + +export const getRollupSearchRequest = (AbstractSearchRequest) => + (class RollupSearchRequest extends AbstractSearchRequest { + async search(options) { + const bodies = Array.isArray(options.body) ? options.body : [options.body]; + const requests = bodies + .map(body => this.callWithRequest(SEARCH_METHOD, { + body, + index: this.indexPattern, + rest_total_hits_as_int: true, + })); + + return await Promise.all(requests); + } + }); diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_request.test.js b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_request.test.js new file mode 100644 index 0000000000000..3c90cad4650e3 --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_request.test.js @@ -0,0 +1,51 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ +import { getRollupSearchRequest } from './rollup_search_request'; + +class AbstractSearchRequest { + indexPattern = 'indexPattern'; + callWithRequest = jest.fn(({ body }) => Promise.resolve(body)); +} + +describe('Rollup search request', () => { + let RollupSearchRequest; + + beforeEach(() => { + RollupSearchRequest = getRollupSearchRequest(AbstractSearchRequest); + }); + + test('should create instance of RollupSearchRequest', () => { + const rollupSearchRequest = new RollupSearchRequest(); + + expect(rollupSearchRequest).toBeInstanceOf(AbstractSearchRequest); + expect(rollupSearchRequest.search).toBeDefined(); + expect(rollupSearchRequest.indexPattern).toBeDefined(); + expect(rollupSearchRequest.callWithRequest).toBeDefined(); + }); + + test('should send one request for single search', async () => { + const rollupSearchRequest = new RollupSearchRequest(); + const body = 'body'; + + await rollupSearchRequest.search({ body }); + + expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledTimes(1); + expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledWith('rollup.search', { + body, + index: 'indexPattern', + rest_total_hits_as_int: true, + }); + }); + + test('should send multiple request for multi search', async () => { + const rollupSearchRequest = new RollupSearchRequest(); + const body = ['firstRequestBody', 'secondRequestBody']; + + await rollupSearchRequest.search({ body }); + + expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledTimes(body.length); + }); +}); diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.js b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.js new file mode 100644 index 0000000000000..a38dc49cac915 --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.js @@ -0,0 +1,67 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ +import { indexBy, isString } from 'lodash'; +import { callWithRequestFactory } from '../call_with_request_factory'; +import { mergeCapabilitiesWithFields } from '../merge_capabilities_with_fields'; +import { getCapabilitiesForRollupIndices } from '../map_capabilities'; + +const ROLLUP_INDEX_CAPABILITIES_METHOD = 'rollup.rollupIndexCapabilities'; +const batchRequestsSupport = false; + +const getRollupIndices = rollupData => Object.keys(rollupData); + +const isIndexPatternContainsWildcard = indexPattern => indexPattern.includes('*'); +const isIndexPatternValid = indexPattern => indexPattern && + isString(indexPattern) && !isIndexPatternContainsWildcard(indexPattern); + +export const getRollupSearchStrategy = (AbstractSearchStrategy, RollupSearchRequest, RollupSearchCapabilities) => + (class RollupSearchStrategy extends AbstractSearchStrategy { + name = 'rollup'; + + constructor(server) { + super(server, callWithRequestFactory, RollupSearchRequest); + } + + getRollupData(req, indexPattern) { + const callWithRequest = this.getCallWithRequestInstance(req); + + return callWithRequest(ROLLUP_INDEX_CAPABILITIES_METHOD, { + indexPattern, + }).catch(() => Promise.resolve({})); + } + + async checkForViability(req, indexPattern) { + let isViable = false; + let capabilities = null; + + if (isIndexPatternValid(indexPattern)) { + const rollupData = await this.getRollupData(req, indexPattern); + const rollupIndices = getRollupIndices(rollupData); + + isViable = rollupIndices.length === 1; + + if (isViable) { + const [rollupIndex] = rollupIndices; + const fieldsCapabilities = getCapabilitiesForRollupIndices(rollupData); + + capabilities = new RollupSearchCapabilities(req, batchRequestsSupport, fieldsCapabilities, rollupIndex); + } + } + + return { + isViable, + capabilities, + }; + } + + async getFieldsForWildcard(req, indexPattern, { fieldsCapabilities, rollupIndex }) { + const fields = await super.getFieldsForWildcard(req, indexPattern); + const fieldsFromFieldCapsApi = indexBy(fields, 'name'); + const rollupIndexCapabilities = fieldsCapabilities[rollupIndex].aggs; + + return mergeCapabilitiesWithFields(rollupIndexCapabilities, fieldsFromFieldCapsApi); + } + }); diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.test.js b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.test.js new file mode 100644 index 0000000000000..f13c2070f713a --- /dev/null +++ b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.test.js @@ -0,0 +1,153 @@ +/* +* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +* or more contributor license agreements. Licensed under the Elastic License; +* you may not use this file except in compliance with the Elastic License. +*/ +import { getRollupSearchStrategy } from './rollup_search_strategy'; + +describe('Rollup Search Strategy', () => { + let RollupSearchStrategy; + let RollupSearchRequest; + let RollupSearchCapabilities; + let callWithRequest; + let rollupResolvedData; + + const server = 'server'; + const request = 'request'; + const indexPattern = 'indexPattern'; + + beforeEach(() => { + class AbstractSearchStrategy { + getCallWithRequestInstance = jest.fn(() => callWithRequest); + + getFieldsForWildcard() { + return [ + { + name: 'day_of_week.terms.value', + type: 'object', + searchable: false, + aggregatable: false, + }, + ]; + } + } + + RollupSearchRequest = jest.fn(); + RollupSearchCapabilities = jest.fn(() => 'capabilities'); + callWithRequest = jest.fn().mockImplementation(() => rollupResolvedData); + + RollupSearchStrategy = getRollupSearchStrategy(AbstractSearchStrategy, RollupSearchRequest, RollupSearchCapabilities); + }); + + test('should create instance of RollupSearchRequest', () => { + const rollupSearchStrategy = new RollupSearchStrategy(server); + + expect(rollupSearchStrategy.name).toBe('rollup'); + }); + + describe('checkForViability', () => { + let rollupSearchStrategy; + const rollupIndex = 'rollupIndex'; + + beforeEach(() => { + rollupSearchStrategy = new RollupSearchStrategy(server); + rollupSearchStrategy.getRollupData = jest.fn(() => ({ + [rollupIndex]: { + rollup_jobs: [{ + job_id: 'test', + rollup_index: rollupIndex, + index_pattern: 'kibana*', + fields: { + order_date: [{ + agg: 'date_histogram', + delay: '1m', + interval: '1m', + time_zone: 'UTC', + }], + day_of_week: [{ + agg: 'terms', + }], + }, + }], + }, + })); + }); + + test('isViable should be false for invalid index', async () => { + const result = await rollupSearchStrategy.checkForViability(request, null); + + expect(result).toEqual({ + isViable: false, + capabilities: null, + }); + }); + + test('should get RollupSearchCapabilities for valid rollup index ', async () => { + await rollupSearchStrategy.checkForViability(request, rollupIndex); + + expect(RollupSearchCapabilities).toHaveBeenCalled(); + }); + }); + + describe('getRollupData', () => { + let rollupSearchStrategy; + + beforeEach(() => { + rollupSearchStrategy = new RollupSearchStrategy(server); + }); + + test('should return rollup data', async () => { + rollupResolvedData = Promise.resolve('data'); + + const rollupData = await rollupSearchStrategy.getRollupData(request, indexPattern); + + expect(callWithRequest).toHaveBeenCalledWith('rollup.rollupIndexCapabilities', { indexPattern }); + expect(rollupSearchStrategy.getCallWithRequestInstance).toHaveBeenCalledWith(request); + expect(rollupData).toBe('data'); + }); + + test('should return empty object in case of exception', async () => { + rollupResolvedData = Promise.reject('data'); + + const rollupData = await rollupSearchStrategy.getRollupData(request, indexPattern); + + expect(rollupData).toEqual({}); + }); + }); + + describe('getFieldsForWildcard', () => { + let rollupSearchStrategy; + let fieldsCapabilities; + + const rollupIndex = 'rollupIndex'; + + beforeEach(() => { + rollupSearchStrategy = new RollupSearchStrategy(server); + fieldsCapabilities = { + [rollupIndex]: { + aggs: { + terms: { + day_of_week: { agg: 'terms' }, + }, + }, + }, + }; + }); + + test('should return fields for wildcard', async () => { + const fields = await rollupSearchStrategy.getFieldsForWildcard(request, indexPattern, + { fieldsCapabilities, rollupIndex }, + ); + + expect(fields).toEqual([ + { + aggregatable: true, + name: 'day_of_week', + readFromDocValues: true, + searchable: true, + type: 'object', + }, + ]); + }); + }); +}); diff --git a/x-pack/plugins/rollup/server/routes/api/index_patterns.js b/x-pack/plugins/rollup/server/routes/api/index_patterns.js index 4b68d3abc0f60..7f760ac515896 100644 --- a/x-pack/plugins/rollup/server/routes/api/index_patterns.js +++ b/x-pack/plugins/rollup/server/routes/api/index_patterns.js @@ -10,6 +10,7 @@ import { wrapEsError, wrapUnknownError } from '../../lib/error_wrappers'; import { licensePreRoutingFactory } from'../../lib/license_pre_routing_factory'; import indexBy from 'lodash/collection/indexBy'; import { getCapabilitiesForRollupIndices } from '../../lib/map_capabilities'; +import { mergeCapabilitiesWithFields } from '../../lib/merge_capabilities_with_fields'; import querystring from 'querystring'; /** @@ -57,7 +58,6 @@ export function registerFieldsForWildcardRoute(server) { const callWithRequest = callWithRequestFactory(server, request); const rollupFields = []; - const rollupFieldNames = []; const fieldsFromFieldCapsApi = indexBy(fields, 'name'); const rollupIndexCapabilities = getCapabilitiesForRollupIndices(await callWithRequest('rollup.rollupIndexCapabilities', { indexPattern: rollupIndex @@ -66,62 +66,10 @@ export function registerFieldsForWildcardRoute(server) { // Keep meta fields metaFields.forEach(field => fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field])); - // Merge rollup capabilities information with field information - Object.keys(rollupIndexCapabilities).forEach(agg => { - - // Field names of the aggregation - const fields = Object.keys(rollupIndexCapabilities[agg]); - - // Default field information - const defaultField = { - name: null, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }; - - // Date histogram agg only ever has one field defined, let date type overwrite a - // previous type if defined (such as number from max and min aggs). - if(agg === 'date_histogram') { - const timeFieldName = fields[0]; - const fieldCapsKey = `${timeFieldName}.${agg}.timestamp`; - const newField = { - ...fieldsFromFieldCapsApi[fieldCapsKey], - ...defaultField, - name: timeFieldName, - }; - const existingField = rollupFields.find(field => field.name === timeFieldName); - - if(existingField) { - Object.assign(existingField, newField); - } else { - rollupFieldNames.push(timeFieldName); - rollupFields.push(newField); - } - } - // For all other aggs, filter out ones that have already been added to the field list - // because the same field can be part of multiple aggregations, but end consumption - // doesn't differentiate fields based on their aggregation abilities. - else { - rollupFields.push( - ...fields - .filter(field => !rollupFieldNames.includes(field)) - .map(field => { - // Expand each field into object format that end consumption expects. - const fieldCapsKey = `${field}.${agg}.value`; - rollupFieldNames.push(field); - return { - ...fieldsFromFieldCapsApi[fieldCapsKey], - ...defaultField, - name: field, - }; - }) - ); - } - }); + const mergedRollupFields = mergeCapabilitiesWithFields(rollupIndexCapabilities, fieldsFromFieldCapsApi, rollupFields); return { - fields: rollupFields + fields: [ ...rollupFields, ...mergedRollupFields ] }; } catch(err) { if (isEsError(err)) { diff --git a/x-pack/plugins/searchprofiler/public/filters/ms_to_pretty.js b/x-pack/plugins/searchprofiler/public/filters/ms_to_pretty.js index 18d1c7ddc4729..aa088ffc46c59 100644 --- a/x-pack/plugins/searchprofiler/public/filters/ms_to_pretty.js +++ b/x-pack/plugins/searchprofiler/public/filters/ms_to_pretty.js @@ -30,4 +30,4 @@ export function msToPretty(ms, precision) { ms /= 24; return ms.toFixed(precision) + 'd'; -} \ No newline at end of file +} diff --git a/x-pack/plugins/searchprofiler/public/templates/default_query.js b/x-pack/plugins/searchprofiler/public/templates/default_query.js index 13d9719e6085d..afab7e808eb1a 100644 --- a/x-pack/plugins/searchprofiler/public/templates/default_query.js +++ b/x-pack/plugins/searchprofiler/public/templates/default_query.js @@ -8,4 +8,4 @@ export const defaultQuery = `{ "query":{ "match_all" : {} } -}`; \ No newline at end of file +}`; diff --git a/x-pack/plugins/searchprofiler/server/routes/profile.js b/x-pack/plugins/searchprofiler/server/routes/profile.js index 72953c3b37690..b1ba7527b69dd 100644 --- a/x-pack/plugins/searchprofiler/server/routes/profile.js +++ b/x-pack/plugins/searchprofiler/server/routes/profile.js @@ -48,4 +48,4 @@ export function profileRoute(server, commonRouteConfig) { } }); -} \ No newline at end of file +} diff --git a/x-pack/plugins/security/common/constants.js b/x-pack/plugins/security/common/constants.js index bc74ebb4bfeec..5fb316b772508 100644 --- a/x-pack/plugins/security/common/constants.js +++ b/x-pack/plugins/security/common/constants.js @@ -6,4 +6,4 @@ export const GLOBAL_RESOURCE = '*'; export const IGNORED_TYPES = ['space']; -export const REALMS_ELIGIBLE_FOR_PASSWORD_CHANGE = ['reserved', 'native']; \ No newline at end of file +export const REALMS_ELIGIBLE_FOR_PASSWORD_CHANGE = ['reserved', 'native']; diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx index 6ec7c6c7f0e8a..4b58cdba41057 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx @@ -196,19 +196,21 @@ export class IndexPrivilegeForm extends Component { {!this.props.isReservedRole && ( - - } + { // @ts-ignore - compressed={true} - checked={this.state.queryExpanded} - onChange={this.toggleDocumentQuery} - /> + + } + compressed={true} + checked={this.state.queryExpanded} + onChange={this.toggleDocumentQuery} + /> + } )} {this.state.queryExpanded && ( diff --git a/x-pack/plugins/security/public/views/management/edit_user.js b/x-pack/plugins/security/public/views/management/edit_user.js index 0a0a21d1bcb95..23da6db3fb1b3 100644 --- a/x-pack/plugins/security/public/views/management/edit_user.js +++ b/x-pack/plugins/security/public/views/management/edit_user.js @@ -38,7 +38,7 @@ routes.when(`${EDIT_USERS_PATH}/:username?`, { : getCreateUserBreadcrumbs ), controllerAs: 'editUser', - controller($scope, $route, kbnUrl, Notifier, confirmModal, $http) { + controller($scope, $route, kbnUrl, $http) { $scope.$on('$destroy', () => { const elem = document.getElementById('editUserReactRoot'); if (elem) { diff --git a/x-pack/plugins/spaces/public/views/nav_control/components/spaces_menu.tsx b/x-pack/plugins/spaces/public/views/nav_control/components/spaces_menu.tsx index 322af5670cd64..825a14e7928bb 100644 --- a/x-pack/plugins/spaces/public/views/nav_control/components/spaces_menu.tsx +++ b/x-pack/plugins/spaces/public/views/nav_control/components/spaces_menu.tsx @@ -106,19 +106,21 @@ class SpacesMenuUI extends Component { const { intl } = this.props; return (
- + + }
); }; diff --git a/x-pack/plugins/spaces/public/views/nav_control/nav_control_popover.tsx b/x-pack/plugins/spaces/public/views/nav_control/nav_control_popover.tsx index fea41c1461bac..4ae7319b4d542 100644 --- a/x-pack/plugins/spaces/public/views/nav_control/nav_control_popover.tsx +++ b/x-pack/plugins/spaces/public/views/nav_control/nav_control_popover.tsx @@ -80,6 +80,7 @@ export class NavControlPopover extends Component { } return ( + // @ts-ignore repositionOnScroll doesn't exist on EuiPopover { closePopover={this.closeSpaceSelector} anchorPosition={this.props.anchorPosition} panelPaddingSize="none" - // @ts-ignore repositionOnScroll={true} withTitle={this.props.anchorPosition.includes('down')} ownFocus diff --git a/x-pack/plugins/spaces/public/views/space_selector/space_selector.tsx b/x-pack/plugins/spaces/public/views/space_selector/space_selector.tsx index e9a7124cdf58d..776e5f848296f 100644 --- a/x-pack/plugins/spaces/public/views/space_selector/space_selector.tsx +++ b/x-pack/plugins/spaces/public/views/space_selector/space_selector.tsx @@ -160,16 +160,18 @@ class SpaceSelectorUI extends Component { } return ( - + { + // @ts-ignore onSearch doesn't exist on EuiFieldSearch + + } ); }; diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 7c928298995a3..3b92cd2151b2b 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -85,7 +85,7 @@ export function createTestHandler(initApiFn: (server: any, preCheckLicenseImpl: get: (key: string) => config[key], }; - server.decorate('server', 'config', jest.fn(() => mockConfig)); + server.decorate('server', 'config', jest.fn(() => mockConfig)); initApiFn(server, pre); diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index efdcace70641c..b7575863f4fbf 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3292,7 +3292,6 @@ "xpack.apm.apmDescription": "自动从您的应用程序内收集深入全面的性能指标和错误。", "xpack.apm.apmForESDescription": "Elastic Stack 的 APM", "xpack.apm.breadcrumb.errorsTitle": "错误", - "xpack.apm.breadcrumb.invalidLicenseTitle": "许可无效", "xpack.apm.breadcrumb.metricsTitle": "指标", "xpack.apm.breadcrumb.servicesTitle": "服务", "xpack.apm.breadcrumb.tracesTitle": "追溯", @@ -3335,7 +3334,6 @@ "xpack.apm.formatters.transactionsPerMinLabel": "tpm", "xpack.apm.home.servicesTabLabel": "服务", "xpack.apm.home.tracesTabLabel": "追溯", - "xpack.apm.invalidLicenseLabel": "许可无效", "xpack.apm.kueryBar.indexPatternMissingWarningMessage": "没有标题为 “{apmIndexPatternTitle}” 的可用 APM 索引模式。要使用查询栏,请选择通过{setupInstructionsLink}导入 APM 索引模式。", "xpack.apm.kueryBar.searchPlaceholder": "搜索事务和错误……(例如 {queryExample}", "xpack.apm.kueryBar.setupInstructionsLinkLabel": "设置说明", @@ -4107,7 +4105,6 @@ "xpack.indexLifecycleMgmt.editPolicy.warmPhase.warmPhaseDescriptionMessage": "您仍在查询自己的索引,但其为只读。您可以将分片分配给效率较低的硬件。为了获取更快的搜索,您可以减少分片数目并强制合并段。", "xpack.indexLifecycleMgmt.editPolicy.warmPhase.warmPhaseLabel": "温阶段", "xpack.indexLifecycleMgmt.hotPhase.daysLabel": "天", - "xpack.indexLifecycleMgmt.hotPhase.documentsLabel": "文档", "xpack.indexLifecycleMgmt.hotPhase.enableRolloverLabel": "启用滚动更新", "xpack.indexLifecycleMgmt.hotPhase.gigabytesLabel": "千兆字节", "xpack.indexLifecycleMgmt.hotPhase.hoursLabel": "小时", @@ -8219,4 +8216,4 @@ "xpack.watcher.watchActionsTitle": "满足后将执行 {watchActionsCount, plural, one{# 个操作} other {# 个操作}}", "xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.test.ts index 6c9bc91a9c46f..a67f01e5fe68c 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.test.ts @@ -6,7 +6,7 @@ import Boom from 'boom'; import moment from 'moment'; -import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; + import { IndexGroup, REINDEX_OP_TYPE, @@ -22,7 +22,7 @@ import { LOCK_WINDOW, ReindexActions, reindexActionsFactory } from './reindex_ac describe('ReindexActions', () => { let client: jest.Mocked; - let callCluster: jest.Mock; + let callCluster: jest.Mock; let actions: ReindexActions; const unimplemented = (name: string) => () => diff --git a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts index e00812cbfc745..c6f2a86d3101c 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION, @@ -25,7 +24,7 @@ import { describe('reindexService', () => { let actions: jest.Mocked; - let callCluster: jest.Mock; + let callCluster: jest.Mock; let xpackInfo: { feature: jest.Mocked }; let service: ReindexService; @@ -63,7 +62,7 @@ describe('reindexService', () => { }, })), }; - service = reindexServiceFactory(callCluster, xpackInfo as any, actions); + service = reindexServiceFactory(callCluster as any, xpackInfo as any, actions); }); describe('hasRequiredPrivileges', () => { @@ -303,7 +302,7 @@ describe('reindexService', () => { const findSpy = jest.spyOn(service, 'findReindexOperation').mockResolvedValueOnce({ id: '2', attributes: { indexName: 'myIndex', status: ReindexStatus.inProgress }, - }); + } as any); await service.pauseReindexOperation('myIndex'); @@ -355,7 +354,7 @@ describe('reindexService', () => { const findSpy = jest.spyOn(service, 'findReindexOperation').mockResolvedValueOnce({ id: '2', attributes: { indexName: 'myIndex', status: ReindexStatus.paused }, - }); + } as any); await service.resumeReindexOperation('myIndex'); @@ -412,7 +411,7 @@ describe('reindexService', () => { lastCompletedStep: ReindexStep.reindexStarted, reindexTaskId: '999333', }, - }); + } as any); callCluster.mockResolvedValueOnce(true); await service.cancelReindexing('myIndex'); diff --git a/x-pack/plugins/uptime/common/graphql/introspection.json b/x-pack/plugins/uptime/common/graphql/introspection.json index c4d40b1d95668..59428b55e6fbd 100644 --- a/x-pack/plugins/uptime/common/graphql/introspection.json +++ b/x-pack/plugins/uptime/common/graphql/introspection.json @@ -183,11 +183,7 @@ "defaultValue": null } ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "MonitorChartEntry", "ofType": null } - }, + "type": { "kind": "OBJECT", "name": "MonitorChart", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, @@ -1575,11 +1571,11 @@ { "kind": "OBJECT", "name": "LatestMonitor", - "description": "", + "description": "Represents the latest recorded information about a monitor.", "fields": [ { "name": "id", - "description": "", + "description": "The ID of the monitor represented by this data.", "args": [], "type": { "kind": "NON_NULL", @@ -1591,7 +1587,7 @@ }, { "name": "ping", - "description": "", + "description": "Information from the latest document.", "args": [], "type": { "kind": "OBJECT", "name": "Ping", "ofType": null }, "isDeprecated": false, @@ -1599,7 +1595,7 @@ }, { "name": "upSeries", - "description": "", + "description": "Buckets of recent up count status data.", "args": [], "type": { "kind": "LIST", @@ -1611,7 +1607,7 @@ }, { "name": "downSeries", - "description": "", + "description": "Buckets of recent down count status data.", "args": [], "type": { "kind": "LIST", @@ -1793,86 +1789,133 @@ }, { "kind": "OBJECT", - "name": "MonitorChartEntry", - "description": "", + "name": "MonitorChart", + "description": "The data used to populate the monitor charts.", "fields": [ { - "name": "maxContent", - "description": "", + "name": "durationArea", + "description": "The max and min values for the monitor duration.", "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxResponse", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxValidate", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "MonitorDurationAreaPoint", "ofType": null } + } + } + }, "isDeprecated": false, "deprecationReason": null }, { - "name": "maxTotal", - "description": "", + "name": "durationLine", + "description": "The average values for the monitor duration.", "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MonitorDurationAveragePoint", + "ofType": null + } + } + } + }, "isDeprecated": false, "deprecationReason": null }, { - "name": "maxWriteRequest", - "description": "", + "name": "status", + "description": "The counts of up/down checks for the monitor.", "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "StatusData", "ofType": null } + } + } + }, "isDeprecated": false, "deprecationReason": null }, { - "name": "maxTcpRtt", - "description": "", + "name": "statusMaxCount", + "description": "The maximum status doc count in this chart.", "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } + }, "isDeprecated": false, "deprecationReason": null }, { - "name": "maxDuration", - "description": "", + "name": "durationMaxValue", + "description": "The maximum duration value in this chart.", "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } + }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "MonitorDurationAreaPoint", + "description": "Represents a monitor's duration performance in microseconds at a point in time.", + "fields": [ { - "name": "minDuration", - "description": "", + "name": "x", + "description": "The timeseries value for this point in time.", "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null } + }, "isDeprecated": false, "deprecationReason": null }, { - "name": "avgDuration", - "description": "", + "name": "yMin", + "description": "The min duration value in microseconds at this time.", "args": [], - "type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null }, + "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "status", - "description": "", + "name": "yMax", + "description": "The max duration value in microseconds at this point.", "args": [], - "type": { "kind": "OBJECT", "name": "StatusData", "ofType": null }, + "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "isDeprecated": false, "deprecationReason": null } @@ -1882,22 +1925,36 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "Float", + "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", - "name": "DataPoint", - "description": "", + "name": "MonitorDurationAveragePoint", + "description": "Represents the average monitor duration ms at a point in time.", "fields": [ { "name": "x", - "description": "", + "description": "The timeseries value for this point.", "args": [], - "type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null } + }, "isDeprecated": false, "deprecationReason": null }, { "name": "y", - "description": "", + "description": "The average duration ms for the monitor.", "args": [], "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, "isDeprecated": false, @@ -1909,32 +1966,26 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, { "kind": "OBJECT", "name": "StatusData", - "description": "", + "description": "Represents a bucket of monitor status information.", "fields": [ { "name": "x", - "description": "", + "description": "The timeseries point for this status data.", "args": [], - "type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null } + }, "isDeprecated": false, "deprecationReason": null }, { "name": "up", - "description": "", + "description": "The value of up counts for this point.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, @@ -1942,7 +1993,7 @@ }, { "name": "down", - "description": "", + "description": "The value for down counts for this point.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, @@ -1950,7 +2001,7 @@ }, { "name": "total", - "description": "", + "description": "The total down counts for this point.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, @@ -2854,6 +2905,33 @@ } ], "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "DataPoint", + "description": "", + "fields": [ + { + "name": "x", + "description": "", + "args": [], + "type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "y", + "description": "", + "args": [], + "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null } ], "directives": [ diff --git a/x-pack/plugins/uptime/common/graphql/types.ts b/x-pack/plugins/uptime/common/graphql/types.ts index df88b55df718b..07b44eafb3d98 100644 --- a/x-pack/plugins/uptime/common/graphql/types.ts +++ b/x-pack/plugins/uptime/common/graphql/types.ts @@ -24,7 +24,7 @@ export interface Query { getSnapshot?: Snapshot | null; - getMonitorChartsData?: (MonitorChartEntry | null)[] | null; + getMonitorChartsData?: MonitorChart | null; getLatestMonitors: Ping[]; @@ -307,14 +307,15 @@ export interface DocCount { export interface LatestMonitorsResult { monitors?: LatestMonitor[] | null; } - +/** Represents the latest recorded information about a monitor. */ export interface LatestMonitor { + /** The ID of the monitor represented by this data. */ id: MonitorKey; - + /** Information from the latest document. */ ping?: Ping | null; - + /** Buckets of recent up count status data. */ upSeries?: (MonitorSeriesPoint | null)[] | null; - + /** Buckets of recent down count status data. */ downSeries?: (MonitorSeriesPoint | null)[] | null; } @@ -351,42 +352,44 @@ export interface HistogramDataPoint { y?: UnsignedInteger | null; } - -export interface MonitorChartEntry { - maxContent?: DataPoint | null; - - maxResponse?: DataPoint | null; - - maxValidate?: DataPoint | null; - - maxTotal?: DataPoint | null; - - maxWriteRequest?: DataPoint | null; - - maxTcpRtt?: DataPoint | null; - - maxDuration?: DataPoint | null; - - minDuration?: DataPoint | null; - - avgDuration?: DataPoint | null; - - status?: StatusData | null; -} - -export interface DataPoint { - x?: UnsignedInteger | null; - +/** The data used to populate the monitor charts. */ +export interface MonitorChart { + /** The max and min values for the monitor duration. */ + durationArea: MonitorDurationAreaPoint[]; + /** The average values for the monitor duration. */ + durationLine: MonitorDurationAveragePoint[]; + /** The counts of up/down checks for the monitor. */ + status: StatusData[]; + /** The maximum status doc count in this chart. */ + statusMaxCount: number; + /** The maximum duration value in this chart. */ + durationMaxValue: number; +} +/** Represents a monitor's duration performance in microseconds at a point in time. */ +export interface MonitorDurationAreaPoint { + /** The timeseries value for this point in time. */ + x: UnsignedInteger; + /** The min duration value in microseconds at this time. */ + yMin?: number | null; + /** The max duration value in microseconds at this point. */ + yMax?: number | null; +} +/** Represents the average monitor duration ms at a point in time. */ +export interface MonitorDurationAveragePoint { + /** The timeseries value for this point. */ + x: UnsignedInteger; + /** The average duration ms for the monitor. */ y?: number | null; } - +/** Represents a bucket of monitor status information. */ export interface StatusData { - x?: UnsignedInteger | null; - + /** The timeseries point for this status data. */ + x: UnsignedInteger; + /** The value of up counts for this point. */ up?: number | null; - + /** The value for down counts for this point. */ down?: number | null; - + /** The total down counts for this point. */ total?: number | null; } @@ -424,6 +427,12 @@ export interface MonitorPageTitle { name?: string | null; } +export interface DataPoint { + x?: UnsignedInteger | null; + + y?: number | null; +} + // ==================================================== // Arguments // ==================================================== diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap new file mode 100644 index 0000000000000..18ced34e904b6 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap @@ -0,0 +1,355 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MonitorCharts component renders the component without errors 1`] = ` + + + + +

+ +

+
+ + + + + + +
+ + +

+ +

+
+ + + + + + +
+
+
+`; diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx b/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx new file mode 100644 index 0000000000000..869f9c056d44b --- /dev/null +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { MonitorCharts } from '../monitor_charts'; + +describe('MonitorCharts component', () => { + const chartResponse = { + monitorChartsData: { + durationArea: [ + { x: 1548697620000, yMin: 106421, yMax: 3120392 }, + { x: 1548697920000, yMin: 121653, yMax: 3955186 }, + { x: 1548698220000, yMin: 118224, yMax: 3705359 }, + { x: 1548698520000, yMin: 123345, yMax: 6669234 }, + { x: 1548698820000, yMin: 117268, yMax: 3955729 }, + { x: 1548699120000, yMin: 122110, yMax: 4045216 }, + { x: 1548699420000, yMin: 120015, yMax: 3682859 }, + { x: 1548699720000, yMin: 114751, yMax: 3701297 }, + { x: 1548700020000, yMin: 111949, yMax: 3632224 }, + { x: 1548700320000, yMin: 105126, yMax: 3801401 }, + { x: 1548700620000, yMin: 123639, yMax: 3925269 }, + ], + durationLine: [ + { x: 1548697620000, y: 743928.2027027027 }, + { x: 1548697920000, y: 766840.0133333333 }, + { x: 1548698220000, y: 786970.8266666667 }, + { x: 1548698520000, y: 781064.7808219178 }, + { x: 1548698820000, y: 741563.04 }, + { x: 1548699120000, y: 759354.6756756756 }, + { x: 1548699420000, y: 737533.3866666667 }, + { x: 1548699720000, y: 728669.0266666666 }, + { x: 1548700020000, y: 719951.64 }, + { x: 1548700320000, y: 769181.7866666666 }, + { x: 1548700620000, y: 740805.2666666667 }, + ], + status: [ + { x: 1548697620000, up: 74, down: null, total: 74 }, + { x: 1548697920000, up: 75, down: null, total: 75 }, + { x: 1548698220000, up: 75, down: null, total: 75 }, + { x: 1548698520000, up: 73, down: null, total: 73 }, + { x: 1548698820000, up: 75, down: null, total: 75 }, + { x: 1548699120000, up: 74, down: null, total: 74 }, + { x: 1548699420000, up: 75, down: null, total: 75 }, + { x: 1548699720000, up: 75, down: null, total: 75 }, + { x: 1548700020000, up: 75, down: null, total: 75 }, + { x: 1548700320000, up: 75, down: null, total: 75 }, + { x: 1548700620000, up: 75, down: null, total: 75 }, + ], + statusMaxCount: 75, + durationMaxValue: 6669234, + }, + }; + + it('renders the component without errors', () => { + const component = shallowWithIntl( + + ); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/functional/index.ts b/x-pack/plugins/uptime/public/components/functional/index.ts index 1207d58d05cd9..e400643a1b04c 100644 --- a/x-pack/plugins/uptime/public/components/functional/index.ts +++ b/x-pack/plugins/uptime/public/components/functional/index.ts @@ -9,6 +9,7 @@ export { EmptyStatusBar } from './empty_status_bar'; export { ErrorList } from './error_list'; export { FilterBar } from './filter_bar'; export { FilterBarLoading } from './filter_bar_loading'; +export { MonitorCharts } from './monitor_charts'; export { MonitorList } from './monitor_list'; export { MonitorPageTitle } from './monitor_page_title'; export { MonitorStatusBar } from './monitor_status_bar'; diff --git a/x-pack/plugins/uptime/public/components/functional/monitor_charts.tsx b/x-pack/plugins/uptime/public/components/functional/monitor_charts.tsx new file mode 100644 index 0000000000000..334a32054f7ad --- /dev/null +++ b/x-pack/plugins/uptime/public/components/functional/monitor_charts.tsx @@ -0,0 +1,147 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + // @ts-ignore missing typings + EuiAreaSeries, + EuiFlexGroup, + EuiFlexItem, + // @ts-ignore missing typings + EuiLineSeries, + EuiPanel, + // @ts-ignore missing typings + EuiSeriesChart, + // @ts-ignore missing typings + EuiSeriesChartUtils, + // @ts-ignore missing typings + EuiSpacer, + // @ts-ignore missing typings + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React, { Fragment } from 'react'; +import { MonitorChart } from '../../../common/graphql/types'; +import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../lib/helper'; + +interface MonitorChartsProps { + checkDomainLimits: number[]; + crosshairLocation: number; + danger: string; + durationDomainLimits: number[]; + monitorChartData: MonitorChart; + primary: string; + secondary: string; + updateCrosshairLocation: (crosshairLocation: number) => void; +} + +export const MonitorCharts = ({ + checkDomainLimits, + crosshairLocation, + danger, + durationDomainLimits, + monitorChartData: { durationArea, durationLine, status }, + primary, + secondary, + updateCrosshairLocation, +}: MonitorChartsProps) => ( + + + + +

+ +

+
+ + + + ({ + x, + y0: microsToMillis(yMin), + y: microsToMillis(yMax), + }))} + curve="curveBasis" + /> + ({ + x, + y: microsToMillis(y), + }))} + /> + + +
+ + +

+ +

+
+ + + ({ x, y: up }))} + curve="curveBasis" + color={primary} + /> + ({ x, y: down }))} + color={danger} + /> + + +
+
+
+); diff --git a/x-pack/plugins/uptime/public/components/functional/monitor_status_bar.tsx b/x-pack/plugins/uptime/public/components/functional/monitor_status_bar.tsx index e06265dd78221..e4f171d75a966 100644 --- a/x-pack/plugins/uptime/public/components/functional/monitor_status_bar.tsx +++ b/x-pack/plugins/uptime/public/components/functional/monitor_status_bar.tsx @@ -11,7 +11,7 @@ import moment from 'moment'; import React from 'react'; interface Props { - duration?: number; + duration?: number | null; url?: string; status?: string; timestamp?: string; @@ -50,19 +50,21 @@ export const MonitorStatusBar = ({ timestamp, url, duration, status }: Props) =>
- - - + {!!duration && ( + + + + )} duration / 1000, + render: (duration: number) => microsToMillis(duration), }, { field: 'error.type', diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts.ts b/x-pack/plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts.ts index 2016f65fbb385..7fffec4440703 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts.ts +++ b/x-pack/plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts.ts @@ -6,22 +6,19 @@ import gql from 'graphql-tag'; -export const createGetMonitorChartsQueryString = ` +export const getMonitorChartsQueryString = ` query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId: String!) { monitorChartsData: getMonitorChartsData( monitorId: $monitorId dateRangeStart: $dateRangeStart dateRangeEnd: $dateRangeEnd ) { - minDuration { + durationArea { x - y - } - maxDuration { - x - y + yMin + yMax } - avgDuration { + durationLine { x y } @@ -31,10 +28,12 @@ query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId down total } + statusMaxCount + durationMaxValue } } `; export const createGetMonitorChartsQuery = gql` - ${createGetMonitorChartsQueryString} + ${getMonitorChartsQueryString} `; diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts_query.tsx b/x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts_query.tsx index 3076585496b5d..11dbf6781d121 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts_query.tsx @@ -4,28 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - // @ts-ignore missing typings - EuiAreaSeries, - EuiFlexGroup, - EuiFlexItem, - // @ts-ignore missing typings - EuiLineSeries, - EuiPanel, - // @ts-ignore missing typings - EuiSeriesChart, - // @ts-ignore missing typings - EuiSeriesChartUtils, - // @ts-ignore missing typings - EuiSpacer, - // @ts-ignore missing typings - EuiTitle, -} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React, { Fragment } from 'react'; +import React from 'react'; import { Query } from 'react-apollo'; +import { MonitorChart } from '../../../../common/graphql/types'; +import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper'; import { UptimeCommonProps } from '../../../uptime_app'; +import { MonitorCharts } from '../../functional'; import { createGetMonitorChartsQuery } from './get_monitor_charts'; interface MonitorChartsProps { @@ -72,125 +57,27 @@ export class MonitorChartsQuery extends React.Component { - avgDurationSeries.push(avgDuration); - areaDurationSeries.push({ x: minDuration.x, y0: minDuration.y, y: maxDuration.y }); - downSeries.push({ x: status.x, y: status.down }); - upSeries.push({ x: status.x, y: status.up }); - checksSeries.push({ x: status.x, y: status.total }); - }); + const { + monitorChartsData, + monitorChartsData: { durationMaxValue, statusMaxCount }, + }: { monitorChartsData: MonitorChart } = data; - // As above, we are building a domain size for the chart to use. - // Without this code the chart could render data outside of the field. - const checksDomain = upSeries.concat(downSeries).map(({ y }) => y); - const checkDomainLimits = [0, Math.max(...checksDomain)]; - const durationDomain = avgDurationSeries.concat(areaDurationSeries); - const durationDomainLimits = [0, Math.max(...durationDomain.map(({ y }) => y))]; + const durationMax = microsToMillis(durationMaxValue); + // These limits provide domain sizes for the charts + const checkDomainLimits = [0, statusMaxCount]; + const durationDomainLimits = [0, durationMax ? durationMax : 0]; return ( - - - - -

- -

-
- - - - - - - -
- - -

- -

-
- - - - - - -
-
-
+ ); }} diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/__tests__/format_duration.test.ts b/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/__tests__/format_duration.test.ts deleted file mode 100644 index 4889909d98b75..0000000000000 --- a/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/__tests__/format_duration.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { formatDuration } from '../format_duration'; - -describe('formatDuration', () => { - it('returns 0 for undefined', () => { - const result = formatDuration(undefined); - expect(result).toEqual(0); - }); - - it('returns 0 for NaN', () => { - const result = formatDuration(NaN); - expect(result).toEqual(0); - }); - - it('returns duration value in ms', () => { - const duration = 320000; // microseconds - expect(formatDuration(duration)).toEqual(320); - }); -}); diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/format_duration.ts b/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/format_duration.ts deleted file mode 100644 index 955eb81f9a77a..0000000000000 --- a/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/format_duration.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export const formatDuration = (duration: number | undefined): number => { - if (duration === undefined) { - return 0; - } - // TODO: formatting should not be performed this way, remove bare number - return isNaN(duration) ? 0 : duration / 1000; -}; diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar_query.tsx b/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar_query.tsx index f0e101da4b278..872680cc57d42 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar_query.tsx @@ -10,9 +10,9 @@ import { get } from 'lodash'; import React from 'react'; import { Query } from 'react-apollo'; import { Ping } from 'x-pack/plugins/uptime/common/graphql/types'; +import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper'; import { UptimeCommonProps } from '../../../uptime_app'; import { EmptyStatusBar, MonitorStatusBar } from '../../functional'; -import { formatDuration } from './format_duration'; import { getMonitorStatusBarQuery } from './get_monitor_status_bar'; interface MonitorStatusBarProps { @@ -63,16 +63,11 @@ export const MonitorStatusBarQuery = ({ } const { monitor, timestamp, url } = monitorStatus[0]; const status = get(monitor, 'status', undefined); - const duration = parseInt(get(monitor, 'duration.us'), 10); + const duration = microsToMillis(get(monitor, 'duration.us', null)); const full = get(url, 'full', undefined); return ( - + ); }} diff --git a/x-pack/plugins/uptime/public/lib/helper/__test__/convert_measurements.test.ts b/x-pack/plugins/uptime/public/lib/helper/__test__/convert_measurements.test.ts new file mode 100644 index 0000000000000..211c8092b24a7 --- /dev/null +++ b/x-pack/plugins/uptime/public/lib/helper/__test__/convert_measurements.test.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { convertMicrosecondsToMilliseconds } from '../convert_measurements'; + +describe('convertMicrosecondsToMilliseconds', () => { + it('converts microseconds to millis', () => { + const microValue = 3425342; + const result = convertMicrosecondsToMilliseconds(microValue); + expect(result).toEqual(3425); + }); + it('returns null for null parameter', () => { + expect(convertMicrosecondsToMilliseconds(null)).toBeNull(); + }); + it('returns undefined for undefined parameter', () => { + expect(convertMicrosecondsToMilliseconds(undefined)).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/uptime/public/lib/helper/convert_measurements.ts b/x-pack/plugins/uptime/public/lib/helper/convert_measurements.ts new file mode 100644 index 0000000000000..b826cf660cf75 --- /dev/null +++ b/x-pack/plugins/uptime/public/lib/helper/convert_measurements.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +const NUM_MICROSECONDS_IN_MILLISECOND = 1000; + +/** + * This simply converts microseconds to milliseconds. People tend to prefer ms to us + * when visualizaing request duration times. + */ +export const convertMicrosecondsToMilliseconds = (microseconds: number | null | undefined) => + microseconds ? Math.round(microseconds / NUM_MICROSECONDS_IN_MILLISECOND) : microseconds; diff --git a/x-pack/test/types/leadfoot.d.ts b/x-pack/plugins/uptime/public/lib/helper/index.ts similarity index 59% rename from x-pack/test/types/leadfoot.d.ts rename to x-pack/plugins/uptime/public/lib/helper/index.ts index a9a081afa8114..d0e5f633535e7 100644 --- a/x-pack/test/types/leadfoot.d.ts +++ b/x-pack/plugins/uptime/public/lib/helper/index.ts @@ -4,9 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -declare module 'leadfoot/keys' { - type LeadfootKeys = 'BACKSPACE' | 'ENTER' | 'RETURN'; - - const keys: { [key in LeadfootKeys]: string }; - export default keys; -} +export { convertMicrosecondsToMilliseconds } from './convert_measurements'; diff --git a/x-pack/plugins/uptime/public/uptime_app.tsx b/x-pack/plugins/uptime/public/uptime_app.tsx index 8e18579a2a71f..c4e0389b1bd0d 100644 --- a/x-pack/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/plugins/uptime/public/uptime_app.tsx @@ -23,10 +23,11 @@ import { import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; import { ApolloProvider } from 'react-apollo'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; +import { I18nContext } from 'ui/i18n'; import { overviewBreadcrumb, UMBreadcrumb } from './breadcrumbs'; import { UMGraphQLClient, UMUpdateBreadcrumbs } from './lib/lib'; import { MonitorPage, OverviewPage } from './pages'; @@ -135,7 +136,7 @@ class Application extends React.Component { public render() { const { routerBasename, graphQLClient } = this.props; return ( - + @@ -249,7 +250,7 @@ class Application extends React.Component { - + ); } diff --git a/x-pack/plugins/uptime/server/graphql/monitors/resolvers.ts b/x-pack/plugins/uptime/server/graphql/monitors/resolvers.ts index 11a026da4a075..a4aea6993ecf7 100644 --- a/x-pack/plugins/uptime/server/graphql/monitors/resolvers.ts +++ b/x-pack/plugins/uptime/server/graphql/monitors/resolvers.ts @@ -15,6 +15,7 @@ import { GetMonitorPageTitleQueryArgs, GetMonitorsQueryArgs, GetSnapshotQueryArgs, + MonitorChart, MonitorPageTitle, Ping, Snapshot, @@ -113,8 +114,8 @@ export const createMonitorsResolvers: CreateUMGraphQLResolvers = ( resolver, { monitorId, dateRangeStart, dateRangeEnd }, { req } - ): Promise { - return libs.monitors.getMonitorChartsData(req, monitorId, dateRangeStart, dateRangeEnd); + ): Promise { + return await libs.monitors.getMonitorChartsData(req, monitorId, dateRangeStart, dateRangeEnd); }, async getLatestMonitors( resolver, diff --git a/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts b/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts index 0bc7874f3454d..eb8109841dee6 100644 --- a/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts +++ b/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts @@ -35,24 +35,30 @@ export const monitorsSchema = gql` y: Float } + "Represents a bucket of monitor status information." type StatusData { - x: UnsignedInteger + "The timeseries point for this status data." + x: UnsignedInteger! + "The value of up counts for this point." up: Int + "The value for down counts for this point." down: Int + "The total down counts for this point." total: Int } - type MonitorChartEntry { - maxContent: DataPoint - maxResponse: DataPoint - maxValidate: DataPoint - maxTotal: DataPoint - maxWriteRequest: DataPoint - maxTcpRtt: DataPoint - maxDuration: DataPoint - minDuration: DataPoint - avgDuration: DataPoint - status: StatusData + "The data used to populate the monitor charts." + type MonitorChart { + "The max and min values for the monitor duration." + durationArea: [MonitorDurationAreaPoint!]! + "The average values for the monitor duration." + durationLine: [MonitorDurationAveragePoint!]! + "The counts of up/down checks for the monitor." + status: [StatusData!]! + "The maximum status doc count in this chart." + statusMaxCount: Int! + "The maximum duration value in this chart." + durationMaxValue: Int! } type MonitorKey { @@ -65,10 +71,33 @@ export const monitorsSchema = gql` y: Int } + "Represents a monitor's duration performance in microseconds at a point in time." + type MonitorDurationAreaPoint { + "The timeseries value for this point in time." + x: UnsignedInteger! + "The min duration value in microseconds at this time." + yMin: Float + "The max duration value in microseconds at this point." + yMax: Float + } + + "Represents the average monitor duration ms at a point in time." + type MonitorDurationAveragePoint { + "The timeseries value for this point." + x: UnsignedInteger! + "The average duration ms for the monitor." + y: Float + } + + "Represents the latest recorded information about a monitor." type LatestMonitor { + "The ID of the monitor represented by this data." id: MonitorKey! + "Information from the latest document." ping: Ping + "Buckets of recent up count status data." upSeries: [MonitorSeriesPoint] + "Buckets of recent down count status data." downSeries: [MonitorSeriesPoint] } @@ -104,7 +133,7 @@ export const monitorsSchema = gql` monitorId: String! dateRangeStart: String! dateRangeEnd: String! - ): [MonitorChartEntry] + ): MonitorChart getLatestMonitors(dateRangeStart: String!, dateRangeEnd: String!, monitorId: String): [Ping!]! diff --git a/x-pack/plugins/uptime/server/lib/adapters/monitors/adapter_types.ts b/x-pack/plugins/uptime/server/lib/adapters/monitors/adapter_types.ts index 834091063965f..45ac7e98db09c 100644 --- a/x-pack/plugins/uptime/server/lib/adapters/monitors/adapter_types.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/monitors/adapter_types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { MonitorPageTitle } from 'x-pack/plugins/uptime/common/graphql/types'; +import { MonitorChart, MonitorPageTitle } from '../../../../common/graphql/types'; export interface UMMonitorsAdapter { getMonitorChartsData( @@ -12,7 +12,7 @@ export interface UMMonitorsAdapter { monitorId: string, dateRangeStart: string, dateRangeEnd: string - ): Promise; + ): Promise; getMonitors( request: any, dateRangeStart: string, diff --git a/x-pack/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts b/x-pack/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts index 63242259ab5f7..8fda903ea26cf 100644 --- a/x-pack/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts @@ -10,21 +10,16 @@ import { ErrorListItem, FilterBar, LatestMonitor, + MonitorChart, MonitorKey, MonitorPageTitle, MonitorSeriesPoint, Ping, } from '../../../../common/graphql/types'; -import { getFilteredQuery, getFilteredQueryAndStatusFilter } from '../../helper'; +import { dropLatestBucket, getFilteredQuery, getFilteredQueryAndStatusFilter } from '../../helper'; import { DatabaseAdapter } from '../database'; import { UMMonitorsAdapter } from './adapter_types'; -// the values for these charts are stored as μs, but should be displayed as ms -const formatChartValue = (time: any, chartPoint: any) => ({ - x: time, - y: chartPoint.value === null ? null : chartPoint.value / 1000, -}); - const formatStatusBuckets = (time: any, buckets: any, docCount: any) => { let up = null; let down = null; @@ -62,7 +57,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { monitorId: string, dateRangeStart: string, dateRangeEnd: string - ): Promise { + ): Promise { const params = { index: INDEX_NAMES.HEARTBEAT, body: { @@ -79,15 +74,9 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { timeseries: { auto_date_histogram: { field: '@timestamp', - buckets: 50, + buckets: 25, }, aggs: { - max_content: { max: { field: 'http.rtt.content.us' } }, - max_response: { max: { field: 'http.rtt.response_header.us' } }, - max_validate: { max: { field: 'http.rtt.validate.us' } }, - max_total: { max: { field: 'http.rtt.total.us' } }, - max_write_request: { max: { field: 'http.rtt.write_request.us' } }, - max_tcp_rtt: { max: { field: 'tcp.rtt.connect.us' } }, status: { terms: { field: 'monitor.status', size: 2, shard_size: 2 } }, duration: { stats: { field: 'monitor.duration.us' } }, }, @@ -97,33 +86,49 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { }; const result = await this.database.search(request, params); - const buckets = get(result, 'aggregations.timeseries.buckets', []); + const buckets = dropLatestBucket(get(result, 'aggregations.timeseries.buckets', [])); - return buckets.map( - ({ - key, - max_content, - duration: { avg, max, min }, - max_write_request, - max_validate, - max_tcp_rtt, - max_response, - max_total, - status, - doc_count, - }: any) => ({ - maxContent: formatChartValue(key, max_content), - maxWriteRequest: formatChartValue(key, max_write_request), - maxValidate: formatChartValue(key, max_validate), - maxTcpRtt: formatChartValue(key, max_tcp_rtt), - maxResponse: formatChartValue(key, max_response), - maxTotal: formatChartValue(key, max_total), - avgDuration: formatChartValue(key, { value: avg }), - maxDuration: formatChartValue(key, { value: max }), - minDuration: formatChartValue(key, { value: min }), - status: formatStatusBuckets(key, status.buckets, doc_count), - }) - ); + /** + * The code below is responsible for formatting the aggregation data we fetched above in a way + * that the chart components used by the client understands. + * There are five required values. Two are lists of points that conform to a simple (x,y) structure. + * + * The third list is for an area chart expressing a range, and it requires an (x,y,y0) structure, + * where y0 is the min value for the point and y is the max. + * + * Additionally, we supply the maximum value for duration and status, so the corresponding charts know + * what the domain size should be. + */ + const monitorChartsData: MonitorChart = { + durationArea: [], + durationLine: [], + status: [], + durationMaxValue: 0, + statusMaxCount: 0, + }; + + buckets.forEach(bucket => { + const x = get(bucket, 'key'); + const docCount = get(bucket, 'doc_count', 0); + // update the maximum value for each point + monitorChartsData.statusMaxCount = Math.max(docCount, monitorChartsData.statusMaxCount); + monitorChartsData.durationMaxValue = Math.max( + monitorChartsData.durationMaxValue, + get(bucket, 'duration.max', 0) + ); + + // these points express a range that will be displayed as an area chart + monitorChartsData.durationArea.push({ + x, + yMin: get(bucket, 'duration.min', null), + yMax: get(bucket, 'duration.max', null), + }); + monitorChartsData.durationLine.push({ x, y: get(bucket, 'duration.avg', null) }); + monitorChartsData.status.push( + formatStatusBuckets(x, get(bucket, 'status.buckets', []), docCount) + ); + }); + return monitorChartsData; } /** diff --git a/x-pack/plugins/uptime/server/lib/domains/monitors.ts b/x-pack/plugins/uptime/server/lib/domains/monitors.ts index 839b0df9eb126..ec2bb37c771c0 100644 --- a/x-pack/plugins/uptime/server/lib/domains/monitors.ts +++ b/x-pack/plugins/uptime/server/lib/domains/monitors.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { MonitorPageTitle } from '../../../common/graphql/types'; +import { MonitorChart, MonitorPageTitle } from '../../../common/graphql/types'; import { UMMonitorsAdapter } from '../adapters/monitors'; export class UMMonitorsDomain { @@ -17,7 +17,7 @@ export class UMMonitorsDomain { monitorId: string, dateRangeStart: string, dateRangeEnd: string - ): Promise { + ): Promise { return this.adapter.getMonitorChartsData(request, monitorId, dateRangeStart, dateRangeEnd); } diff --git a/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/drop_latest_buckets.test.ts.snap b/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/drop_latest_buckets.test.ts.snap new file mode 100644 index 0000000000000..db05bb02be8a9 --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/drop_latest_buckets.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`dropLatestBucket drops the last of a list with greater length than 1 1`] = ` +Array [ + Object { + "prop": "val", + }, +] +`; diff --git a/x-pack/plugins/uptime/server/lib/helper/__test__/drop_latest_buckets.test.ts b/x-pack/plugins/uptime/server/lib/helper/__test__/drop_latest_buckets.test.ts new file mode 100644 index 0000000000000..57ae48f0c7b63 --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/helper/__test__/drop_latest_buckets.test.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { dropLatestBucket } from '../drop_latest_bucket'; + +describe('dropLatestBucket', () => { + it('drops the last of a list with greater length than 1', () => { + const testData = [{ prop: 'val' }, { prop: 'val' }]; + const result = dropLatestBucket(testData); + expect(result).toMatchSnapshot(); + }); + it('returns an empty list when length === 1', () => { + const testData = [{ prop: 'val' }]; + const result = dropLatestBucket(testData); + expect(result).toEqual([]); + }); + it('returns an empty list when length === 0', () => { + const testData: any[] = []; + const result = dropLatestBucket(testData); + expect(result).toEqual([]); + }); +}); diff --git a/x-pack/plugins/uptime/server/lib/helper/drop_latest_bucket.ts b/x-pack/plugins/uptime/server/lib/helper/drop_latest_bucket.ts new file mode 100644 index 0000000000000..4d072266fa4ea --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/helper/drop_latest_bucket.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/** + * We've had numerous requests to not display semi-full buckets (i.e. it is 13:01 and the + * bounds of our bucket are 13:00-13:05). If the first bucket isn't done filling, we'll + * start out with nothing returned, otherwise we drop the most recent bucket. + * @param buckets The bucket list + */ +export const dropLatestBucket = (buckets: any[]) => + buckets.length > 1 ? buckets.slice(0, buckets.length - 1) : []; diff --git a/x-pack/plugins/uptime/server/lib/helper/format_es_buckets_for_histogram.ts b/x-pack/plugins/uptime/server/lib/helper/format_es_buckets_for_histogram.ts index fb545d415bb82..7007d28b1af2b 100644 --- a/x-pack/plugins/uptime/server/lib/helper/format_es_buckets_for_histogram.ts +++ b/x-pack/plugins/uptime/server/lib/helper/format_es_buckets_for_histogram.ts @@ -5,6 +5,7 @@ */ import { UMESBucket, UMESHistogramBucket } from '../adapters/database'; +import { dropLatestBucket } from './drop_latest_bucket'; /** * The charting library we're currently using requires histogram data points have an @@ -27,7 +28,7 @@ export function formatEsBucketsForHistogram( const TERMINAL_INDEX = buckets.length - 1; const { key: terminalBucketTime } = buckets[TERMINAL_INDEX]; // drop the most recent bucket to avoid returning incomplete bucket - return buckets.slice(0, TERMINAL_INDEX).map((item, index, array) => { + return dropLatestBucket(buckets).map((item, index, array) => { const { key } = item; const nextItem = array[index + 1]; const bucketSize = nextItem ? Math.abs(nextItem.key - key) : Math.abs(terminalBucketTime - key); diff --git a/x-pack/plugins/uptime/server/lib/helper/index.ts b/x-pack/plugins/uptime/server/lib/helper/index.ts index 658071e6cdad5..2d779416fa2bd 100644 --- a/x-pack/plugins/uptime/server/lib/helper/index.ts +++ b/x-pack/plugins/uptime/server/lib/helper/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +export { dropLatestBucket } from './drop_latest_bucket'; export { formatEsBucketsForHistogram } from './format_es_buckets_for_histogram'; export { getFilteredQuery } from './get_filtered_query'; export { getFilteredQueryAndStatusFilter } from './get_filtered_query_and_status'; diff --git a/x-pack/plugins/watcher/common/constants/lists.js b/x-pack/plugins/watcher/common/constants/lists.js index 10c8f2f74e72f..da89b99f828ba 100644 --- a/x-pack/plugins/watcher/common/constants/lists.js +++ b/x-pack/plugins/watcher/common/constants/lists.js @@ -7,4 +7,4 @@ // Durations are in ms export const LISTS = { NEW_ITEMS_HIGHLIGHT_DURATION: 1 * 1000 -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/watcher/common/constants/plugin.js b/x-pack/plugins/watcher/common/constants/plugin.js index 2ab0032e6cbfc..bcff927863019 100644 --- a/x-pack/plugins/watcher/common/constants/plugin.js +++ b/x-pack/plugins/watcher/common/constants/plugin.js @@ -6,4 +6,4 @@ export const PLUGIN = { ID: 'watcher' -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/watcher/common/constants/routes.js b/x-pack/plugins/watcher/common/constants/routes.js index 1e40b01ebebe1..97ae0ee6de181 100644 --- a/x-pack/plugins/watcher/common/constants/routes.js +++ b/x-pack/plugins/watcher/common/constants/routes.js @@ -6,4 +6,4 @@ export const ROUTES = { API_ROOT: '/api/watcher', -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/watcher/common/constants/watch_history.js b/x-pack/plugins/watcher/common/constants/watch_history.js index a0871bf3fc5c5..3fad569ab7878 100644 --- a/x-pack/plugins/watcher/common/constants/watch_history.js +++ b/x-pack/plugins/watcher/common/constants/watch_history.js @@ -6,4 +6,4 @@ export const WATCH_HISTORY = { INITIAL_RANGE: 'now-1h' -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/watcher/public/components/chart_tooltip/chart_tooltip.js b/x-pack/plugins/watcher/public/components/chart_tooltip/chart_tooltip.js index 21272a3569bd3..7102567fb3cbf 100644 --- a/x-pack/plugins/watcher/public/components/chart_tooltip/chart_tooltip.js +++ b/x-pack/plugins/watcher/public/components/chart_tooltip/chart_tooltip.js @@ -67,4 +67,4 @@ app.directive('chartTooltip', function () { } } }; -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/watcher/public/components/chart_tooltip/index.js b/x-pack/plugins/watcher/public/components/chart_tooltip/index.js index 65326aa72fb42..09d3ddf9ae8d6 100644 --- a/x-pack/plugins/watcher/public/components/chart_tooltip/index.js +++ b/x-pack/plugins/watcher/public/components/chart_tooltip/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './chart_tooltip'; \ No newline at end of file +import './chart_tooltip'; diff --git a/x-pack/plugins/watcher/public/components/flot_chart/index.js b/x-pack/plugins/watcher/public/components/flot_chart/index.js index 24b727061d238..c95a866839fab 100644 --- a/x-pack/plugins/watcher/public/components/flot_chart/index.js +++ b/x-pack/plugins/watcher/public/components/flot_chart/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './flot_chart'; \ No newline at end of file +import './flot_chart'; diff --git a/x-pack/plugins/watcher/public/components/threshold_preview_chart/index.js b/x-pack/plugins/watcher/public/components/threshold_preview_chart/index.js index 72a9b6076891c..fbf2da1b51526 100644 --- a/x-pack/plugins/watcher/public/components/threshold_preview_chart/index.js +++ b/x-pack/plugins/watcher/public/components/threshold_preview_chart/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './threshold_preview_chart'; \ No newline at end of file +import './threshold_preview_chart'; diff --git a/x-pack/plugins/watcher/public/models/watch_history_item/index.js b/x-pack/plugins/watcher/public/models/watch_history_item/index.js index 2c6b8ce2f4360..a3d73334543ed 100644 --- a/x-pack/plugins/watcher/public/models/watch_history_item/index.js +++ b/x-pack/plugins/watcher/public/models/watch_history_item/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { WatchHistoryItem } from './watch_history_item'; \ No newline at end of file +export { WatchHistoryItem } from './watch_history_item'; diff --git a/x-pack/plugins/watcher/public/sections/watch_detail/components/watch_history_range_filter/index.js b/x-pack/plugins/watcher/public/sections/watch_detail/components/watch_history_range_filter/index.js index a6bdd5620ec63..dd189310a75a3 100644 --- a/x-pack/plugins/watcher/public/sections/watch_detail/components/watch_history_range_filter/index.js +++ b/x-pack/plugins/watcher/public/sections/watch_detail/components/watch_history_range_filter/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './watch_history_range_filter'; \ No newline at end of file +import './watch_history_range_filter'; diff --git a/x-pack/plugins/watcher/public/services/license/index.js b/x-pack/plugins/watcher/public/services/license/index.js index d30d544e4b927..8be8fb5ccbc64 100644 --- a/x-pack/plugins/watcher/public/services/license/index.js +++ b/x-pack/plugins/watcher/public/services/license/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './license_service.factory'; \ No newline at end of file +import './license_service.factory'; diff --git a/x-pack/plugins/watcher/public/services/watches/index.js b/x-pack/plugins/watcher/public/services/watches/index.js index 773b4894b47ab..9a52e4f276fde 100644 --- a/x-pack/plugins/watcher/public/services/watches/index.js +++ b/x-pack/plugins/watcher/public/services/watches/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './watches_service.factory'; \ No newline at end of file +import './watches_service.factory'; diff --git a/x-pack/plugins/watcher/server/lib/call_with_request_factory/call_with_request_factory.js b/x-pack/plugins/watcher/server/lib/call_with_request_factory/call_with_request_factory.js index abdf3efce3999..f60f825b98004 100644 --- a/x-pack/plugins/watcher/server/lib/call_with_request_factory/call_with_request_factory.js +++ b/x-pack/plugins/watcher/server/lib/call_with_request_factory/call_with_request_factory.js @@ -8,10 +8,7 @@ import { once } from 'lodash'; import { elasticsearchJsPlugin } from '../elasticsearch_js_plugin'; const callWithRequest = once((server) => { - const config = { - plugins: [ elasticsearchJsPlugin ], - ...server.config().get('elasticsearch') - }; + const config = { plugins: [ elasticsearchJsPlugin ] }; const cluster = server.plugins.elasticsearch.createCluster('watcher', config); return cluster.callWithRequest; diff --git a/x-pack/plugins/watcher/server/lib/check_license/check_license.js b/x-pack/plugins/watcher/server/lib/check_license/check_license.js index 9353283e7e55a..2b318c4ddd885 100644 --- a/x-pack/plugins/watcher/server/lib/check_license/check_license.js +++ b/x-pack/plugins/watcher/server/lib/check_license/check_license.js @@ -71,4 +71,4 @@ export function checkLicense(xpackLicenseInfo) { showLinks: true, enableLinks: true }; -} \ No newline at end of file +} diff --git a/x-pack/plugins/watcher/server/lib/check_license/index.js b/x-pack/plugins/watcher/server/lib/check_license/index.js index a6c7fae3e1adc..f2c070fd44b6e 100644 --- a/x-pack/plugins/watcher/server/lib/check_license/index.js +++ b/x-pack/plugins/watcher/server/lib/check_license/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { checkLicense } from './check_license'; \ No newline at end of file +export { checkLicense } from './check_license'; diff --git a/x-pack/plugins/watcher/server/lib/error_wrappers/wrap_unknown_error.js b/x-pack/plugins/watcher/server/lib/error_wrappers/wrap_unknown_error.js index 4b865880ae20d..ffd915c513362 100644 --- a/x-pack/plugins/watcher/server/lib/error_wrappers/wrap_unknown_error.js +++ b/x-pack/plugins/watcher/server/lib/error_wrappers/wrap_unknown_error.js @@ -14,4 +14,4 @@ import Boom from 'boom'; */ export function wrapUnknownError(err) { return Boom.boomify(err); -} \ No newline at end of file +} diff --git a/x-pack/plugins/watcher/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js b/x-pack/plugins/watcher/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js index 16139b000e61c..582c021892d42 100644 --- a/x-pack/plugins/watcher/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js +++ b/x-pack/plugins/watcher/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js @@ -88,4 +88,4 @@ describe('fetch_all_from_scroll', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/watcher/server/lib/is_es_error_factory/index.js b/x-pack/plugins/watcher/server/lib/is_es_error_factory/index.js index 3675318feb936..441648a8701e0 100644 --- a/x-pack/plugins/watcher/server/lib/is_es_error_factory/index.js +++ b/x-pack/plugins/watcher/server/lib/is_es_error_factory/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { isEsErrorFactory } from './is_es_error_factory'; \ No newline at end of file +export { isEsErrorFactory } from './is_es_error_factory'; diff --git a/x-pack/plugins/watcher/server/lib/is_es_error_factory/is_es_error_factory.js b/x-pack/plugins/watcher/server/lib/is_es_error_factory/is_es_error_factory.js index 51ed6f4dddfe2..80daac5bd496d 100644 --- a/x-pack/plugins/watcher/server/lib/is_es_error_factory/is_es_error_factory.js +++ b/x-pack/plugins/watcher/server/lib/is_es_error_factory/is_es_error_factory.js @@ -15,4 +15,4 @@ export function isEsErrorFactory(server) { return function isEsError(err) { return err instanceof esErrors._Abstract; }; -} \ No newline at end of file +} diff --git a/x-pack/plugins/watcher/server/lib/license_pre_routing_factory/index.js b/x-pack/plugins/watcher/server/lib/license_pre_routing_factory/index.js index a6903bcf11a78..0743e443955f4 100644 --- a/x-pack/plugins/watcher/server/lib/license_pre_routing_factory/index.js +++ b/x-pack/plugins/watcher/server/lib/license_pre_routing_factory/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { licensePreRoutingFactory } from './license_pre_routing_factory'; \ No newline at end of file +export { licensePreRoutingFactory } from './license_pre_routing_factory'; diff --git a/x-pack/plugins/watcher/server/lib/register_license_checker/index.js b/x-pack/plugins/watcher/server/lib/register_license_checker/index.js index 8f888af8f8860..7b0f97c38d129 100644 --- a/x-pack/plugins/watcher/server/lib/register_license_checker/index.js +++ b/x-pack/plugins/watcher/server/lib/register_license_checker/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { registerLicenseChecker } from './register_license_checker'; \ No newline at end of file +export { registerLicenseChecker } from './register_license_checker'; diff --git a/x-pack/plugins/watcher/server/lib/register_license_checker/register_license_checker.js b/x-pack/plugins/watcher/server/lib/register_license_checker/register_license_checker.js index 26b0091ef2190..b05946e60b330 100644 --- a/x-pack/plugins/watcher/server/lib/register_license_checker/register_license_checker.js +++ b/x-pack/plugins/watcher/server/lib/register_license_checker/register_license_checker.js @@ -18,4 +18,4 @@ export function registerLicenseChecker(server) { // to re-compute the license check results for this plugin xpackMainPlugin.info.feature(PLUGIN.ID).registerLicenseCheckResultsGenerator(checkLicense); }); -} \ No newline at end of file +} diff --git a/x-pack/plugins/watcher/server/models/watch_errors/watch_errors.test.js b/x-pack/plugins/watcher/server/models/watch_errors/watch_errors.test.js index edf0c09aa3387..3acc0998863cc 100644 --- a/x-pack/plugins/watcher/server/models/watch_errors/watch_errors.test.js +++ b/x-pack/plugins/watcher/server/models/watch_errors/watch_errors.test.js @@ -31,4 +31,4 @@ describe('watch_errors', () => { }); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/watcher/server/routes/api/watch/action/register_action_routes.js b/x-pack/plugins/watcher/server/routes/api/watch/action/register_action_routes.js index ca940a64578a6..6f2c86664420b 100644 --- a/x-pack/plugins/watcher/server/routes/api/watch/action/register_action_routes.js +++ b/x-pack/plugins/watcher/server/routes/api/watch/action/register_action_routes.js @@ -8,4 +8,4 @@ import { registerAcknowledgeRoute } from './register_acknowledge_route'; export function registerActionRoutes(server) { registerAcknowledgeRoute(server); -} \ No newline at end of file +} diff --git a/x-pack/plugins/watcher/server/routes/api/watch/register_delete_route.js b/x-pack/plugins/watcher/server/routes/api/watch/register_delete_route.js index 3312dc8889382..dc3b015dffa90 100644 --- a/x-pack/plugins/watcher/server/routes/api/watch/register_delete_route.js +++ b/x-pack/plugins/watcher/server/routes/api/watch/register_delete_route.js @@ -47,4 +47,4 @@ export function registerDeleteRoute(server) { pre: [ licensePreRouting ] } }); -} \ No newline at end of file +} diff --git a/x-pack/plugins/watcher/server/routes/api/watches/register_watches_routes.js b/x-pack/plugins/watcher/server/routes/api/watches/register_watches_routes.js index 954114d863711..5f7ae6a5935bd 100644 --- a/x-pack/plugins/watcher/server/routes/api/watches/register_watches_routes.js +++ b/x-pack/plugins/watcher/server/routes/api/watches/register_watches_routes.js @@ -10,4 +10,4 @@ import { registerDeleteRoute } from './register_delete_route'; export function registerWatchesRoutes(server) { registerListRoute(server); registerDeleteRoute(server); -} \ No newline at end of file +} diff --git a/x-pack/plugins/xpack_main/public/components/index.js b/x-pack/plugins/xpack_main/public/components/index.js index c8dc260717da0..4d1ec4f26fffd 100644 --- a/x-pack/plugins/xpack_main/public/components/index.js +++ b/x-pack/plugins/xpack_main/public/components/index.js @@ -13,4 +13,4 @@ export { AddLicense } from '../../../license_management/public/sections/license_ export { BASE_PATH as MANAGEMENT_BASE_PATH } from '../../../license_management/common/constants'; export { TelemetryForm } from './telemetry/telemetry_form'; -export { OptInExampleFlyout } from './telemetry/opt_in_details_component'; \ No newline at end of file +export { OptInExampleFlyout } from './telemetry/opt_in_details_component'; diff --git a/x-pack/plugins/xpack_main/public/components/telemetry/opt_in_details_component.test.js b/x-pack/plugins/xpack_main/public/components/telemetry/opt_in_details_component.test.js index bfc6a6e56e2f8..358735ff95c8f 100644 --- a/x-pack/plugins/xpack_main/public/components/telemetry/opt_in_details_component.test.js +++ b/x-pack/plugins/xpack_main/public/components/telemetry/opt_in_details_component.test.js @@ -13,4 +13,4 @@ describe('OptInDetailsComponent', () => { ({ data: [] }))} onClose={jest.fn()} />) ).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/xpack_main/public/components/telemetry/telemetry_form.js b/x-pack/plugins/xpack_main/public/components/telemetry/telemetry_form.js index 39920d0eccf98..e95f2f2bb8efb 100644 --- a/x-pack/plugins/xpack_main/public/components/telemetry/telemetry_form.js +++ b/x-pack/plugins/xpack_main/public/components/telemetry/telemetry_form.js @@ -185,4 +185,4 @@ export class TelemetryForm extends Component { showExample: !this.state.showExample }); } -} \ No newline at end of file +} diff --git a/x-pack/plugins/xpack_main/public/components/telemetry/telemetry_form.test.js b/x-pack/plugins/xpack_main/public/components/telemetry/telemetry_form.test.js index 7e5bb1c13a6f3..4afe4e2736311 100644 --- a/x-pack/plugins/xpack_main/public/components/telemetry/telemetry_form.test.js +++ b/x-pack/plugins/xpack_main/public/components/telemetry/telemetry_form.test.js @@ -49,4 +49,4 @@ describe('TelemetryForm', () => { />) ).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/xpack_main/public/hacks/welcome_banner/__tests__/click_banner.js b/x-pack/plugins/xpack_main/public/hacks/welcome_banner/__tests__/click_banner.js index 3ef092bde18ec..3a1e528e3fc41 100644 --- a/x-pack/plugins/xpack_main/public/hacks/welcome_banner/__tests__/click_banner.js +++ b/x-pack/plugins/xpack_main/public/hacks/welcome_banner/__tests__/click_banner.js @@ -110,4 +110,4 @@ describe('click_banner', () => { expect(banners.remove.notCalled).to.be(true); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/xpack_main/public/hacks/welcome_banner/__tests__/should_show_banner.js b/x-pack/plugins/xpack_main/public/hacks/welcome_banner/__tests__/should_show_banner.js index 33fde83241f8a..ed9d3e79a0c59 100644 --- a/x-pack/plugins/xpack_main/public/hacks/welcome_banner/__tests__/should_show_banner.js +++ b/x-pack/plugins/xpack_main/public/hacks/welcome_banner/__tests__/should_show_banner.js @@ -74,4 +74,4 @@ describe('should_show_banner', () => { expect(await shouldShowBanner(telemetryOptInProvider, config)).to.be(false); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/xpack_main/public/hacks/welcome_banner/index.js b/x-pack/plugins/xpack_main/public/hacks/welcome_banner/index.js index 001b275c26ffa..2eabe7496b1f2 100644 --- a/x-pack/plugins/xpack_main/public/hacks/welcome_banner/index.js +++ b/x-pack/plugins/xpack_main/public/hacks/welcome_banner/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { injectBanner } from './inject_banner'; \ No newline at end of file +export { injectBanner } from './inject_banner'; diff --git a/x-pack/plugins/xpack_main/public/services/telemetry_opt_in.test.js b/x-pack/plugins/xpack_main/public/services/telemetry_opt_in.test.js index c89ddbacf6725..2d4270b47d661 100644 --- a/x-pack/plugins/xpack_main/public/services/telemetry_opt_in.test.js +++ b/x-pack/plugins/xpack_main/public/services/telemetry_opt_in.test.js @@ -86,4 +86,4 @@ describe('TelemetryOptInProvider', () => { // opt-in change should not be reflected expect(provider.getOptIn()).toEqual(false); }); -}); \ No newline at end of file +}); diff --git a/x-pack/plugins/xpack_main/server/lib/__tests__/call_cluster_factory.js b/x-pack/plugins/xpack_main/server/lib/__tests__/call_cluster_factory.js index cc0b3075629d2..9c7f17a9e507b 100644 --- a/x-pack/plugins/xpack_main/server/lib/__tests__/call_cluster_factory.js +++ b/x-pack/plugins/xpack_main/server/lib/__tests__/call_cluster_factory.js @@ -10,14 +10,10 @@ import { callClusterFactory } from '../call_cluster_factory'; describe('callClusterFactory', () => { - const configGetStub = sinon.stub(); let mockServer; let mockCluster; beforeEach(() => { - configGetStub.withArgs('elasticsearch.username').returns(null); - configGetStub.withArgs('elasticsearch.password').returns(null); - mockCluster = { callWithRequest: sinon.stub().returns(Promise.resolve({ hits: { total: 0 } })), callWithInternalUser: sinon.stub().returns(Promise.resolve({ hits: { total: 0 } })), @@ -27,7 +23,6 @@ describe('callClusterFactory', () => { elasticsearch: { getCluster: sinon.stub().withArgs('admin').returns(mockCluster) } }, log() {}, - config: () => ({ get: configGetStub }) }; }); @@ -67,9 +62,6 @@ describe('callClusterFactory', () => { describe('getCallClusterInternal', () => { it('returns a method that wraps callWithInternalUser', async () => { - configGetStub.withArgs('elasticsearch.username').returns('fakeReqUser'); - configGetStub.withArgs('elasticsearch.password').returns('fakeReqPassword'); - const callCluster = callClusterFactory(mockServer).getCallClusterInternal(); const result = await callCluster('search', { body: { match: { match_all: {} } } }); diff --git a/x-pack/server/lib/__tests__/kibana_state.js b/x-pack/server/lib/__tests__/kibana_state.js index 938c263b8f662..3b0b8f8a2ea2d 100644 --- a/x-pack/server/lib/__tests__/kibana_state.js +++ b/x-pack/server/lib/__tests__/kibana_state.js @@ -125,4 +125,4 @@ describe('Kibana state', function () { }); }); }); -}); \ No newline at end of file +}); diff --git a/x-pack/server/lib/check_license/__tests__/check_license.js b/x-pack/server/lib/check_license/__tests__/check_license.js deleted file mode 100644 index 19a7b56759269..0000000000000 --- a/x-pack/server/lib/check_license/__tests__/check_license.js +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from 'expect.js'; -import { set } from 'lodash'; -import { checkLicense } from '../check_license'; - -describe('check_license', function () { - - let mockLicenseInfo; - beforeEach(() => mockLicenseInfo = {}); - - describe('license information is undefined', () => { - beforeEach(() => mockLicenseInfo = undefined); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - - describe('license information is not available', () => { - beforeEach(() => mockLicenseInfo.isAvailable = () => false); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - - describe('license information is available', () => { - beforeEach(() => { - mockLicenseInfo.isAvailable = () => true; - set(mockLicenseInfo, 'license.getType', () => 'basic'); - }); - - describe('& license is trial, standard, gold, platinum', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); - - describe('& license is active', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true)); - - it('should set isAvailable to true', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); - }); - - it ('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it ('should set enableLinks to true', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); - }); - - it('should not set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.be(undefined); - }); - }); - - describe('& license is expired', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it ('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it ('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - }); - - describe('& license is basic', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); - - describe('& license is active', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true)); - - it('should set isAvailable to true', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); - }); - - it ('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it ('should set enableLinks to true', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); - }); - - it('should not set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.be(undefined); - }); - }); - - describe('& license is expired', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it ('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - }); - }); -}); diff --git a/x-pack/server/lib/check_license/check_license.js b/x-pack/server/lib/check_license/check_license.js index 8a5a7d7029b71..edd88b868c8af 100644 --- a/x-pack/server/lib/check_license/check_license.js +++ b/x-pack/server/lib/check_license/check_license.js @@ -4,55 +4,65 @@ * you may not use this file except in compliance with the Elastic License. */ -export function checkLicense(xpackLicenseInfo) { - const pluginName = 'Index Management'; +import { i18n } from '@kbn/i18n'; +import { RANKED_LICENSE_TYPES } from '../constants'; +import { LICENSE_STATUS } from '../../../common/constants'; + +export function checkLicense(pluginName, minimumLicenseRequired, xpackLicenseInfo) { + if(!RANKED_LICENSE_TYPES.includes(minimumLicenseRequired)) { + throw new Error(`Invalid license type supplied to checkLicense: ${minimumLicenseRequired}`); + } // If, for some reason, we cannot get the license information // from Elasticsearch, assume worst case and disable if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) { return { - isAvailable: false, - showLinks: true, - enableLinks: false, - message: `You cannot use ${pluginName} because license information is not available at this time.` + status: LICENSE_STATUS.UNAVAILABLE, + message: i18n.translate( + 'xpack.server.checkLicense.errorUnavailableMessage', + { + defaultMessage: 'You cannot use {pluginName} because license information is not available at this time.', + values: { pluginName }, + }, + ), }; } - const VALID_LICENSE_MODES = [ - 'trial', - 'basic', - 'standard', - 'gold', - 'platinum' - ]; - - const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES); - const isLicenseActive = xpackLicenseInfo.license.isActive(); - const licenseType = xpackLicenseInfo.license.getType(); + const { license } = xpackLicenseInfo; + const isLicenseModeValid = license.isOneOf([...RANKED_LICENSE_TYPES].splice(RANKED_LICENSE_TYPES.indexOf(minimumLicenseRequired))); + const isLicenseActive = license.isActive(); + const licenseType = license.getType(); // License is not valid if (!isLicenseModeValid) { return { - isAvailable: false, - showLinks: false, - message: `Your ${licenseType} license does not support ${pluginName}. Please upgrade your license.` + status: LICENSE_STATUS.INVALID, + message: i18n.translate( + 'xpack.server.checkLicense.errorUnsupportedMessage', + { + defaultMessage: 'Your {licenseType} license does not support {pluginName}. Please upgrade your license.', + values: { licenseType, pluginName }, + }, + ), }; } // License is valid but not active if (!isLicenseActive) { return { - isAvailable: false, - showLinks: true, - enableLinks: false, - message: `You cannot use ${pluginName} because your ${licenseType} license has expired.` + status: LICENSE_STATUS.EXPIRED, + message: i18n.translate( + 'xpack.server.checkLicense.errorExpiredMessage', + { + defaultMessage: 'You cannot use {pluginName} because your {licenseType} license has expired', + values: { licenseType, pluginName }, + }, + ), }; } // License is valid and active return { - isAvailable: true, - showLinks: true, - enableLinks: true + status: LICENSE_STATUS.VALID, }; } diff --git a/x-pack/server/lib/check_license/check_license.test.js b/x-pack/server/lib/check_license/check_license.test.js new file mode 100644 index 0000000000000..b72fa3a0180c8 --- /dev/null +++ b/x-pack/server/lib/check_license/check_license.test.js @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { set } from 'lodash'; +import { checkLicense } from './check_license'; +import { LICENSE_STATUS } from '../../../common/constants'; + +describe('check_license', function () { + + const pluginName = 'Foo'; + const minimumLicenseRequired = 'basic'; + let mockLicenseInfo; + beforeEach(() => mockLicenseInfo = {}); + + describe('license information is undefined', () => { + beforeEach(() => mockLicenseInfo = undefined); + + it('should set status to unavailable', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).status).toBe(LICENSE_STATUS.UNAVAILABLE); + }); + + it('should set a message', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).message).not.toBe(undefined); + }); + }); + + describe('license information is not available', () => { + beforeEach(() => mockLicenseInfo.isAvailable = () => false); + + it('should set status to unavailable', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).status).toBe(LICENSE_STATUS.UNAVAILABLE); + }); + + it('should set a message', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).message).not.toBe(undefined); + }); + }); + + describe('license information is available', () => { + beforeEach(() => { + mockLicenseInfo.isAvailable = () => true; + set(mockLicenseInfo, 'license.getType', () => 'basic'); + }); + + describe('& license is trial, standard, gold, platinum', () => { + beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); + + describe('& license is active', () => { + beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true)); + + it('should set status to valid', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).status).toBe(LICENSE_STATUS.VALID); + }); + + it('should not set a message', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).message).toBe(undefined); + }); + }); + + describe('& license is expired', () => { + beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false)); + + it('should set status to inactive', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).status).toBe(LICENSE_STATUS.EXPIRED); + }); + + it('should set a message', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).message).not.toBe(undefined); + }); + }); + }); + + describe('& license is basic', () => { + beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); + + describe('& license is active', () => { + beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true)); + + it('should set status to valid', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).status).toBe(LICENSE_STATUS.VALID); + }); + + it('should not set a message', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).message).toBe(undefined); + }); + }); + + describe('& license is expired', () => { + beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false)); + + it('should set status to inactive', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).status).toBe(LICENSE_STATUS.EXPIRED); + }); + + it('should set a message', () => { + expect(checkLicense(pluginName, minimumLicenseRequired, mockLicenseInfo).message).not.toBe(undefined); + }); + }); + }); + }); +}); diff --git a/x-pack/server/lib/check_license/index.js b/x-pack/server/lib/check_license/index.js index a6c7fae3e1adc..f2c070fd44b6e 100644 --- a/x-pack/server/lib/check_license/index.js +++ b/x-pack/server/lib/check_license/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { checkLicense } from './check_license'; \ No newline at end of file +export { checkLicense } from './check_license'; diff --git a/x-pack/server/lib/constants.js b/x-pack/server/lib/constants.js index 0dd2bcdcb7fdf..a63cd9046124c 100644 --- a/x-pack/server/lib/constants.js +++ b/x-pack/server/lib/constants.js @@ -6,3 +6,10 @@ export const XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING = 'xPack:defaultAdminEmail'; export const XPACK_INFO_API_DEFAULT_POLL_FREQUENCY_IN_MILLIS = 30001; // 30 seconds +export const RANKED_LICENSE_TYPES = [ + 'basic', + 'standard', + 'gold', + 'platinum', + 'trial', +]; diff --git a/x-pack/server/lib/create_router/error_wrappers/wrap_unknown_error.js b/x-pack/server/lib/create_router/error_wrappers/wrap_unknown_error.js index 4b865880ae20d..ffd915c513362 100644 --- a/x-pack/server/lib/create_router/error_wrappers/wrap_unknown_error.js +++ b/x-pack/server/lib/create_router/error_wrappers/wrap_unknown_error.js @@ -14,4 +14,4 @@ import Boom from 'boom'; */ export function wrapUnknownError(err) { return Boom.boomify(err); -} \ No newline at end of file +} diff --git a/x-pack/server/lib/create_router/is_es_error_factory/index.js b/x-pack/server/lib/create_router/is_es_error_factory/index.js index 3675318feb936..441648a8701e0 100644 --- a/x-pack/server/lib/create_router/is_es_error_factory/index.js +++ b/x-pack/server/lib/create_router/is_es_error_factory/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { isEsErrorFactory } from './is_es_error_factory'; \ No newline at end of file +export { isEsErrorFactory } from './is_es_error_factory'; diff --git a/x-pack/server/lib/create_router/is_es_error_factory/is_es_error_factory.js b/x-pack/server/lib/create_router/is_es_error_factory/is_es_error_factory.js index 51ed6f4dddfe2..80daac5bd496d 100644 --- a/x-pack/server/lib/create_router/is_es_error_factory/is_es_error_factory.js +++ b/x-pack/server/lib/create_router/is_es_error_factory/is_es_error_factory.js @@ -15,4 +15,4 @@ export function isEsErrorFactory(server) { return function isEsError(err) { return err instanceof esErrors._Abstract; }; -} \ No newline at end of file +} diff --git a/x-pack/server/lib/create_router/license_pre_routing_factory/__tests__/license_pre_routing_factory.js b/x-pack/server/lib/create_router/license_pre_routing_factory/__tests__/license_pre_routing_factory.js index 359b3fb2ce6f4..6765588134021 100644 --- a/x-pack/server/lib/create_router/license_pre_routing_factory/__tests__/license_pre_routing_factory.js +++ b/x-pack/server/lib/create_router/license_pre_routing_factory/__tests__/license_pre_routing_factory.js @@ -6,6 +6,7 @@ import expect from 'expect.js'; import { licensePreRoutingFactory } from '../license_pre_routing_factory'; +import { LICENSE_STATUS } from '../../../../../common/constants'; describe('license_pre_routing_factory', () => { describe('#reportingFeaturePreRoutingFactory', () => { @@ -26,17 +27,17 @@ describe('license_pre_routing_factory', () => { }; }); - it('only instantiates one instance per server', () => { - const firstInstance = licensePreRoutingFactory(mockServer); - const secondInstance = licensePreRoutingFactory(mockServer); + it('instantiates a new instance per plugin', () => { + const firstInstance = licensePreRoutingFactory(mockServer, 'foo'); + const secondInstance = licensePreRoutingFactory(mockServer, 'bar'); - expect(firstInstance).to.be(secondInstance); + expect(firstInstance).to.not.be(secondInstance); }); - describe('isAvailable is false', () => { + describe('status is invalid', () => { beforeEach(() => { mockLicenseCheckResults = { - isAvailable: false + status: LICENSE_STATUS.INVALID }; }); @@ -51,10 +52,10 @@ describe('license_pre_routing_factory', () => { }); }); - describe('isAvailable is true', () => { + describe('status is valid', () => { beforeEach(() => { mockLicenseCheckResults = { - isAvailable: true + status: LICENSE_STATUS.VALID }; }); diff --git a/x-pack/server/lib/create_router/license_pre_routing_factory/index.js b/x-pack/server/lib/create_router/license_pre_routing_factory/index.js index a6903bcf11a78..0743e443955f4 100644 --- a/x-pack/server/lib/create_router/license_pre_routing_factory/index.js +++ b/x-pack/server/lib/create_router/license_pre_routing_factory/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { licensePreRoutingFactory } from './license_pre_routing_factory'; \ No newline at end of file +export { licensePreRoutingFactory } from './license_pre_routing_factory'; diff --git a/x-pack/server/lib/create_router/license_pre_routing_factory/license_pre_routing_factory.js b/x-pack/server/lib/create_router/license_pre_routing_factory/license_pre_routing_factory.js index 0c5f32b115f6a..be0920d71806d 100644 --- a/x-pack/server/lib/create_router/license_pre_routing_factory/license_pre_routing_factory.js +++ b/x-pack/server/lib/create_router/license_pre_routing_factory/license_pre_routing_factory.js @@ -6,22 +6,21 @@ import { once } from 'lodash'; import { wrapCustomError } from '../error_wrappers'; +import { LICENSE_STATUS } from '../../../../common/constants'; -export const licensePreRoutingFactory = once((server, pluginId) => { - const xpackMainPlugin = server.plugins.xpack_main; - - // License checking and enable/disable logic - function licensePreRouting() { +export const licensePreRoutingFactory = (server, pluginId) => { + const licensePreRouting = () => { + // License checking and enable/disable logic + const xpackMainPlugin = server.plugins.xpack_main; const licenseCheckResults = xpackMainPlugin.info.feature(pluginId).getLicenseCheckResults(); - if (!licenseCheckResults.isAvailable) { + if (licenseCheckResults.status !== LICENSE_STATUS.VALID) { const error = new Error(licenseCheckResults.message); const statusCode = 403; throw wrapCustomError(error, statusCode); } return null; - } - - return licensePreRouting; -}); + }; + return () => once(licensePreRouting)(); +}; diff --git a/x-pack/server/lib/get_client_shield.js b/x-pack/server/lib/get_client_shield.js index b76daa2fa6148..97319b44b1312 100644 --- a/x-pack/server/lib/get_client_shield.js +++ b/x-pack/server/lib/get_client_shield.js @@ -8,11 +8,5 @@ import { once } from 'lodash'; import esShield from './esjs_shield_plugin'; export const getClient = once((server) => { - const config = { - plugins: [esShield], - ...server.config().get('elasticsearch') - }; - const cluster = server.plugins.elasticsearch.createCluster('security', config); - - return cluster; + return server.plugins.elasticsearch.createCluster('security', { plugins: [esShield] }); }); diff --git a/x-pack/server/lib/parse_kibana_state.js b/x-pack/server/lib/parse_kibana_state.js index 2a8b906866a0f..8084a7b19e01a 100644 --- a/x-pack/server/lib/parse_kibana_state.js +++ b/x-pack/server/lib/parse_kibana_state.js @@ -51,4 +51,4 @@ class KibanaState { export function parseKibanaState(query, type) { return new KibanaState(query, type); -} \ No newline at end of file +} diff --git a/x-pack/server/lib/register_license_checker/index.js b/x-pack/server/lib/register_license_checker/index.js index 8f888af8f8860..7b0f97c38d129 100644 --- a/x-pack/server/lib/register_license_checker/index.js +++ b/x-pack/server/lib/register_license_checker/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { registerLicenseChecker } from './register_license_checker'; \ No newline at end of file +export { registerLicenseChecker } from './register_license_checker'; diff --git a/x-pack/server/lib/register_license_checker/register_license_checker.js b/x-pack/server/lib/register_license_checker/register_license_checker.js index 39ed2edf7880a..5545aedfdb652 100644 --- a/x-pack/server/lib/register_license_checker/register_license_checker.js +++ b/x-pack/server/lib/register_license_checker/register_license_checker.js @@ -7,7 +7,7 @@ import { mirrorPluginStatus } from '../mirror_plugin_status'; import { checkLicense } from '../check_license'; -export function registerLicenseChecker(server, pluginId) { +export function registerLicenseChecker(server, pluginId, pluginName, minimumLicenseRequired) { const xpackMainPlugin = server.plugins.xpack_main; const thisPlugin = server.plugins[pluginId]; @@ -15,6 +15,8 @@ export function registerLicenseChecker(server, pluginId) { xpackMainPlugin.status.once('green', () => { // Register a function that is called whenever the xpack info changes, // to re-compute the license check results for this plugin - xpackMainPlugin.info.feature(pluginId).registerLicenseCheckResultsGenerator(checkLicense); + xpackMainPlugin.info.feature(pluginId).registerLicenseCheckResultsGenerator((xpackLicenseInfo) => { + return checkLicense(pluginName, minimumLicenseRequired, xpackLicenseInfo); + }); }); } diff --git a/x-pack/tasks/build.js b/x-pack/tasks/build.js index 0ccbbf082315c..82ccc9c75bd6f 100644 --- a/x-pack/tasks/build.js +++ b/x-pack/tasks/build.js @@ -4,20 +4,45 @@ * you may not use this file except in compliance with the Elastic License. */ +import del from 'del'; import { resolve } from 'path'; import { writeFileSync } from 'fs'; import pluginHelpers from '@kbn/plugin-helpers'; import { ToolingLog } from '@kbn/dev-utils'; import { generateNoticeFromSource } from '../../src/dev'; +async function moveFiles(gulp, src, dest) { + return new Promise((resolve, reject) => { + gulp.src(src) + .pipe(gulp.dest(dest)) + .on('finish', resolve) + .on('error', reject); + }); +} + export default (gulp, { buildTarget }) => { gulp.task('build', ['clean', 'report', 'prepare:build'], async () => { + const buildRoot = resolve(buildTarget, 'kibana/x-pack'); await pluginHelpers.run('build', { skipArchive: true, buildDestination: buildTarget, }); - const buildRoot = resolve(buildTarget, 'kibana/x-pack'); + // NOTE: In order to prevent ending up with transpiled js files + // in the repository, we have set the outDir on x-pack tsconfig file + // to be the same as the intermediateBuildDirectory defined on the package.json + // As result of it, we need to move the transpiled js files for the correct folder + // and in the end deleting the generated outDir from the intermediateBuildDirectory. + // + //# TODO: This might be able to go away with the upgrade to babel 7 + await moveFiles( + gulp, + resolve(buildRoot, 'x-pack/build/plugin/kibana/x-pack/**/!(*.test).js'), + buildRoot + ); + await del(resolve(buildRoot, 'x-pack')); + //# + const log = new ToolingLog({ level: 'info', writeTo: process.stdout diff --git a/x-pack/tasks/test.js b/x-pack/tasks/test.js index 3016e314098ef..5d6f4a0ab4463 100644 --- a/x-pack/tasks/test.js +++ b/x-pack/tasks/test.js @@ -14,7 +14,6 @@ const MOCHA_OPTIONS = { ui: 'bdd', reporter: createAutoJUnitReporter({ reportName: 'X-Pack Mocha Tests', - rootDirectory: __dirname, }), }; @@ -52,4 +51,4 @@ export default (gulp, { mocha }) => { }); }); }); -}; \ No newline at end of file +}; diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/monitor_charts.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/monitor_charts.json new file mode 100644 index 0000000000000..badcd2094503c --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/monitor_charts.json @@ -0,0 +1,45 @@ +{ + "monitorChartsData": { + "durationArea": [ + { "x": 1548697620000, "yMin": 106421, "yMax": 3120392 }, + { "x": 1548697920000, "yMin": 121653, "yMax": 3955186 }, + { "x": 1548698220000, "yMin": 118224, "yMax": 3705359 }, + { "x": 1548698520000, "yMin": 123345, "yMax": 6669234 }, + { "x": 1548698820000, "yMin": 117268, "yMax": 3955729 }, + { "x": 1548699120000, "yMin": 122110, "yMax": 4045216 }, + { "x": 1548699420000, "yMin": 120015, "yMax": 3682859 }, + { "x": 1548699720000, "yMin": 114751, "yMax": 3701297 }, + { "x": 1548700020000, "yMin": 111949, "yMax": 3632224 }, + { "x": 1548700320000, "yMin": 105126, "yMax": 3801401 }, + { "x": 1548700620000, "yMin": 123639, "yMax": 3925269 } + ], + "durationLine": [ + { "x": 1548697620000, "y": 743928.2027027027 }, + { "x": 1548697920000, "y": 766840.0133333333 }, + { "x": 1548698220000, "y": 786970.8266666667 }, + { "x": 1548698520000, "y": 781064.7808219178 }, + { "x": 1548698820000, "y": 741563.04 }, + { "x": 1548699120000, "y": 759354.6756756756 }, + { "x": 1548699420000, "y": 737533.3866666667 }, + { "x": 1548699720000, "y": 728669.0266666666 }, + { "x": 1548700020000, "y": 719951.64 }, + { "x": 1548700320000, "y": 769181.7866666666 }, + { "x": 1548700620000, "y": 740805.2666666667 } + ], + "status": [ + { "x": 1548697620000, "up": 74, "down": null, "total": 74 }, + { "x": 1548697920000, "up": 75, "down": null, "total": 75 }, + { "x": 1548698220000, "up": 75, "down": null, "total": 75 }, + { "x": 1548698520000, "up": 73, "down": null, "total": 73 }, + { "x": 1548698820000, "up": 75, "down": null, "total": 75 }, + { "x": 1548699120000, "up": 74, "down": null, "total": 74 }, + { "x": 1548699420000, "up": 75, "down": null, "total": 75 }, + { "x": 1548699720000, "up": 75, "down": null, "total": 75 }, + { "x": 1548700020000, "up": 75, "down": null, "total": 75 }, + { "x": 1548700320000, "up": 75, "down": null, "total": 75 }, + { "x": 1548700620000, "up": 75, "down": null, "total": 75 } + ], + "statusMaxCount": 75, + "durationMaxValue": 6669234 + } +} diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/monitor_charts_empty_set.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/monitor_charts_empty_set.json new file mode 100644 index 0000000000000..2c5673e2a86b8 --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/monitor_charts_empty_set.json @@ -0,0 +1,9 @@ +{ + "monitorChartsData": { + "durationArea": [], + "durationLine": [], + "status": [], + "statusMaxCount": 0, + "durationMaxValue": 0 + } +} diff --git a/x-pack/test/api_integration/apis/uptime/graphql/index.js b/x-pack/test/api_integration/apis/uptime/graphql/index.js index e22367aa9acf4..3c55e628c2b6b 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/index.js +++ b/x-pack/test/api_integration/apis/uptime/graphql/index.js @@ -19,6 +19,7 @@ export default function ({ getService, loadTestFile }) { loadTestFile(require.resolve('./doc_count')); loadTestFile(require.resolve('./error_list')); loadTestFile(require.resolve('./filter_bar')); + loadTestFile(require.resolve('./monitor_charts')); loadTestFile(require.resolve('./monitor_list')); loadTestFile(require.resolve('./monitor_status_bar')); loadTestFile(require.resolve('./ping_list')); diff --git a/x-pack/test/api_integration/apis/uptime/graphql/monitor_charts.js b/x-pack/test/api_integration/apis/uptime/graphql/monitor_charts.js new file mode 100644 index 0000000000000..26e73fca2d80a --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/graphql/monitor_charts.js @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from 'expect.js'; +import { getMonitorChartsQueryString } from '../../../../../plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts'; +import monitorCharts from './fixtures/monitor_charts'; +import monitorChartsEmptySet from './fixtures/monitor_charts_empty_set'; + +export default function ({ getService }) { + describe('monitorCharts query', () => { + const supertest = getService('supertest'); + + it('will fetch a series of data points for monitor duration and status', async () => { + const getMonitorChartsQuery = { + operationName: 'MonitorCharts', + query: getMonitorChartsQueryString, + variables: { + dateRangeStart: '2019-01-28T17:40:08.078Z', + dateRangeEnd: '2019-01-28T19:00:16.078Z', + monitorId: 'auto-http-0X131221E73F825974', + }, + }; + const { + body: { data }, + } = await supertest + .post('/api/uptime/graphql') + .set('kbn-xsrf', 'foo') + .send({ ...getMonitorChartsQuery }); + expect(data).to.eql(monitorCharts); + }); + + it('will fetch empty sets for a date range with no data', async () => { + const getMonitorChartsQuery = { + operationName: 'MonitorCharts', + query: getMonitorChartsQueryString, + variables: { + dateRangeStart: '2002-01-28T17:40:08.078Z', + dateRangeEnd: '2002-01-28T19:00:16.078Z', + monitorId: 'auto-http-0X131221E73F825974', + }, + }; + const { + body: { data }, + } = await supertest + .post('/api/uptime/graphql') + .set('kbn-xsrf', 'foo') + .send({ ...getMonitorChartsQuery }); + expect(data).to.eql(monitorChartsEmptySet); + }); + }); +} diff --git a/x-pack/test/api_integration/services/es.js b/x-pack/test/api_integration/services/es.js index 5a76ce88665b9..7efbf3a6e8304 100644 --- a/x-pack/test/api_integration/services/es.js +++ b/x-pack/test/api_integration/services/es.js @@ -8,7 +8,7 @@ import { format as formatUrl } from 'url'; import elasticsearch from 'elasticsearch'; import shieldPlugin from '../../../server/lib/esjs_shield_plugin'; -import { DEFAULT_API_VERSION } from '../../../../src/legacy/core_plugins/elasticsearch/lib/default_api_version'; +import { DEFAULT_API_VERSION } from '../../../../src/core/server/elasticsearch/elasticsearch_config'; export function EsProvider({ getService }) { const config = getService('config'); diff --git a/x-pack/test/api_integration/services/index.js b/x-pack/test/api_integration/services/index.js index 5003927b5332f..96d349f848629 100644 --- a/x-pack/test/api_integration/services/index.js +++ b/x-pack/test/api_integration/services/index.js @@ -8,4 +8,4 @@ export { EsProvider } from './es'; export { EsSupertestWithoutAuthProvider } from './es_supertest_without_auth'; export { SupertestWithoutAuthProvider } from './supertest_without_auth'; export { UsageAPIProvider } from './usage_api'; -export { InfraOpsGraphQLProvider } from './infraops_graphql_client'; \ No newline at end of file +export { InfraOpsGraphQLProvider } from './infraops_graphql_client'; diff --git a/x-pack/test/functional/apps/logstash/pipeline_create.js b/x-pack/test/functional/apps/logstash/pipeline_create.js index 8249cced6d9fc..ef7d17854f691 100644 --- a/x-pack/test/functional/apps/logstash/pipeline_create.js +++ b/x-pack/test/functional/apps/logstash/pipeline_create.js @@ -78,6 +78,7 @@ export default function ({ getService, getPageObjects }) { describe('cancel button', () => { it('discards the pipeline and redirects to the list', async () => { await PageObjects.logstash.gotoPipelineList(); + await pipelineList.assertExists(); const originalRows = await pipelineList.readRows(); await PageObjects.logstash.gotoNewPipelineEditor(); diff --git a/x-pack/test/functional/apps/maps/embeddable/dashboard.js b/x-pack/test/functional/apps/maps/embeddable/dashboard.js new file mode 100644 index 0000000000000..f7e35bd5ca995 --- /dev/null +++ b/x-pack/test/functional/apps/maps/embeddable/dashboard.js @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from 'expect.js'; + +export default function ({ getPageObjects, getService }) { + const PageObjects = getPageObjects(['common', 'dashboard', 'maps']); + const kibanaServer = getService('kibanaServer'); + const filterBar = getService('filterBar'); + const dashboardPanelActions = getService('dashboardPanelActions'); + const inspector = getService('inspector'); + + describe('embed in dashboard', () => { + before(async () => { + await kibanaServer.uiSettings.replace({ + 'defaultIndex': 'c698b940-e149-11e8-a35a-370a8516603a' + }); + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.loadSavedDashboard('map embeddable example'); + }); + + async function getRequestTimestamp() { + await inspector.openInspectorRequestsView(); + const requestStats = await inspector.getTableData(); + const requestTimestamp = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Request timestamp'); + await inspector.close(); + return requestTimestamp; + } + + it('should pass index patterns to container', async () => { + const indexPatterns = await filterBar.getIndexPatterns(); + expect(indexPatterns).to.equal('geo_shapes*,meta_for_geo_shapes*,logstash-*'); + }); + + it('should populate inspector with requests for map embeddable', async () => { + await dashboardPanelActions.openInspectorByTitle('join example'); + const joinExampleRequestNames = await inspector.getRequestNames(); + await inspector.close(); + expect(joinExampleRequestNames).to.equal('geo_shapes*,meta_for_geo_shapes*.shape_name'); + + await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example'); + const gridExampleRequestNames = await inspector.getRequestNames(); + await inspector.close(); + expect(gridExampleRequestNames).to.equal('logstash-*'); + }); + + it('should apply container state (time, query, filters) to embeddable when loaded', async () => { + await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example'); + const requestStats = await inspector.getTableData(); + const totalHits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)'); + await inspector.close(); + expect(totalHits).to.equal('6'); + }); + + it('should apply new container state (time, query, filters) to embeddable', async () => { + await filterBar.selectIndexPattern('logstash-*'); + await filterBar.addFilter('machine.os', 'is', 'win 8'); + await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example'); + const requestStats = await inspector.getTableData(); + const totalHits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)'); + await inspector.close(); + expect(totalHits).to.equal('1'); + }); + + it('should re-fetch query when "refresh" is clicked', async () => { + await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example'); + const beforeQueryRefreshTimestamp = await getRequestTimestamp(); + await PageObjects.maps.refreshQuery(); + await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example'); + const afterQueryRefreshTimestamp = await getRequestTimestamp(); + expect(beforeQueryRefreshTimestamp).not.to.equal(afterQueryRefreshTimestamp); + }); + + it('should re-fetch documents with refresh timer', async () => { + await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example'); + const beforeRefreshTimerTimestamp = await getRequestTimestamp(); + expect(beforeRefreshTimerTimestamp.length).to.be(24); + await PageObjects.maps.triggerSingleRefresh(1000); + await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example'); + const afterRefreshTimerTimestamp = await getRequestTimestamp(); + expect(beforeRefreshTimerTimestamp).not.to.equal(afterRefreshTimerTimestamp); + }); + }); +} diff --git a/x-pack/test/functional/apps/maps/es_geo_grid_source.js b/x-pack/test/functional/apps/maps/es_geo_grid_source.js index b0f086e1cb841..a4663256fc340 100644 --- a/x-pack/test/functional/apps/maps/es_geo_grid_source.js +++ b/x-pack/test/functional/apps/maps/es_geo_grid_source.js @@ -20,7 +20,8 @@ export default function ({ getPageObjects, getService }) { const DATA_CENTER_LAT = 38; async function getRequestTimestamp() { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const requestTimestamp = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Request timestamp'); await inspector.close(); @@ -122,7 +123,8 @@ export default function ({ getPageObjects, getService }) { }); it('should apply query to geotile_grid aggregation request', async () => { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)'); await inspector.close(); @@ -136,7 +138,8 @@ export default function ({ getPageObjects, getService }) { }); it('should contain geotile_grid aggregation elasticsearch request', async () => { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const totalHits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)'); expect(totalHits).to.equal('6'); @@ -195,7 +198,8 @@ export default function ({ getPageObjects, getService }) { }); it('should apply query to geotile_grid aggregation request', async () => { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)'); await inspector.close(); @@ -209,7 +213,8 @@ export default function ({ getPageObjects, getService }) { }); it('should contain geotile_grid aggregation elasticsearch request', async () => { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const totalHits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)'); expect(totalHits).to.equal('6'); diff --git a/x-pack/test/functional/apps/maps/es_search_source.js b/x-pack/test/functional/apps/maps/es_search_source.js index 3258c01983803..c9745ebbecfa2 100644 --- a/x-pack/test/functional/apps/maps/es_search_source.js +++ b/x-pack/test/functional/apps/maps/es_search_source.js @@ -16,7 +16,8 @@ export default function ({ getPageObjects, getService }) { }); async function getRequestTimestamp() { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const requestTimestamp = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Request timestamp'); await inspector.close(); @@ -24,7 +25,8 @@ export default function ({ getPageObjects, getService }) { } async function getHits() { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits'); await inspector.close(); @@ -56,7 +58,8 @@ export default function ({ getPageObjects, getService }) { }); it('should apply query to search request', async () => { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits'); await inspector.close(); diff --git a/x-pack/test/functional/apps/maps/index.js b/x-pack/test/functional/apps/maps/index.js index e7d7f756d767a..d88834de95644 100644 --- a/x-pack/test/functional/apps/maps/index.js +++ b/x-pack/test/functional/apps/maps/index.js @@ -40,6 +40,7 @@ export default function ({ loadTestFile, getService }) { loadTestFile(require.resolve('./joins')); loadTestFile(require.resolve('./add_layer_panel')); loadTestFile(require.resolve('./layer_errors')); + loadTestFile(require.resolve('./embeddable/dashboard')); }); }); } diff --git a/x-pack/test/functional/apps/maps/saved_object_management.js b/x-pack/test/functional/apps/maps/saved_object_management.js index 4af6c90ac0a43..e093d86ebde8b 100644 --- a/x-pack/test/functional/apps/maps/saved_object_management.js +++ b/x-pack/test/functional/apps/maps/saved_object_management.js @@ -66,7 +66,8 @@ export default function ({ getPageObjects, getService }) { }); it('should apply query stored with map', async () => { - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits'); await inspector.close(); @@ -85,7 +86,8 @@ export default function ({ getPageObjects, getService }) { const query = await queryBar.getQueryString(); expect(query).to.equal('machine.os.raw : "win 8"'); - await PageObjects.maps.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); const requestStats = await inspector.getTableData(); await inspector.close(); const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits'); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 24b6dd15cec07..f1cfd20210000 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -231,7 +231,6 @@ export default async function ({ readConfigFile }) { junit: { reportName: 'X-Pack Functional Tests', - rootDirectory: resolve(__dirname, '../../'), }, }; diff --git a/x-pack/test/functional/es_archives/maps/kibana/data.json b/x-pack/test/functional/es_archives/maps/kibana/data.json index 28f14be746c38..7187875ffccb6 100644 --- a/x-pack/test/functional/es_archives/maps/kibana/data.json +++ b/x-pack/test/functional/es_archives/maps/kibana/data.json @@ -392,3 +392,33 @@ } } } + +{ + "type": "doc", + "value": { + "id": "dashboard:19906970-2e40-11e9-85cb-6965aae20f13", + "index": ".kibana", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"}}" + }, + "optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":20,\"i\":\"1\"},\"id\":\"1649cc70-f736-11e8-8ce0-9723965e01e3\",\"panelIndex\":\"1\",\"type\":\"map\",\"version\":\"7.0.0-alpha1\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":20,\"i\":\"2\"},\"id\":\"88845ec0-03ae-11e9-83d4-5b39b6575325\",\"panelIndex\":\"2\",\"type\":\"map\",\"version\":\"7.0.0-alpha1\"}]", + "refreshInterval": { + "pause": true, + "value": 1000 + }, + "timeFrom": "2015-09-20T00:00:00.000Z", + "timeRestore": true, + "timeTo": "2015-09-20T01:00:00.000Z", + "title": "map embeddable example", + "version": 1 + }, + "type": "dashboard", + "updated_at": "2018-04-11T21:57:52.253Z" + } + } +} diff --git a/x-pack/test/functional/page_objects/gis_page.js b/x-pack/test/functional/page_objects/gis_page.js index 9b44244c3da88..122e6434301a9 100644 --- a/x-pack/test/functional/page_objects/gis_page.js +++ b/x-pack/test/functional/page_objects/gis_page.js @@ -258,37 +258,29 @@ export function GisPageProvider({ getService, getPageObjects }) { return await testSubjects.getVisibleText(`layerErrorMessage`); } - async openInspectorView(viewId) { - await inspector.open(); - log.debug(`Open Inspector view ${viewId}`); - await testSubjects.click('inspectorViewChooser'); - await testSubjects.click(viewId); - } - async openInspectorMapView() { - await this.openInspectorView('inspectorViewChooserMap'); - } - - async openInspectorRequestsView() { - await this.openInspectorView('inspectorViewChooserRequests'); + await inspector.openInspectorView('inspectorViewChooserMap'); } // Method should only be used when multiple requests are expected // RequestSelector will only display inspectorRequestChooser when there is more than one request async openInspectorRequest(requestName) { - await this.openInspectorView('inspectorViewChooserRequests'); + await inspector.open(); + await inspector.openInspectorRequestsView(); log.debug(`Open Inspector request ${requestName}`); await testSubjects.click('inspectorRequestChooser'); await testSubjects.click(`inspectorRequestChooser${requestName}`); } async doesInspectorHaveRequests() { - await this.openInspectorRequestsView(); + await inspector.open(); + await inspector.openInspectorRequestsView(); return await testSubjects.exists('inspectorNoRequestsMessage'); } async getMapboxStyle() { log.debug('getMapboxStyle'); + await inspector.open(); await this.openInspectorMapView(); await testSubjects.click('mapboxStyleTab'); const mapboxStyleContainer = await testSubjects.find('mapboxStyleContainer'); diff --git a/x-pack/test/functional/page_objects/infra_home_page.ts b/x-pack/test/functional/page_objects/infra_home_page.ts index 73f80591c2a79..7eb71a1196b76 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -20,7 +20,7 @@ export function InfraHomePageProvider({ getService }: KibanaFunctionalTestDefaul `${testSubjSelector('waffleDatePicker')} .euiDatePicker.euiFieldText` ); - await datePickerInput.type(Array(30).fill(browser.keys.BACKSPACE)); + await datePickerInput.type(Array(30).fill(browser.keys.BACK_SPACE)); await datePickerInput.type([moment(time).format('L LTS'), browser.keys.RETURN]); }, diff --git a/x-pack/test/functional/page_objects/reporting_page.js b/x-pack/test/functional/page_objects/reporting_page.js index fee1b47826e59..8dae2d5e3b524 100644 --- a/x-pack/test/functional/page_objects/reporting_page.js +++ b/x-pack/test/functional/page_objects/reporting_page.js @@ -126,7 +126,7 @@ export function ReportingPageProvider({ getService, getPageObjects }) { async clearToastNotifications() { const toasts = await testSubjects.findAll('toastCloseButton'); - await Promise.all(toasts.map(t => t.click())); + await Promise.all(toasts.map(async t => await t.click())); } async getQueueReportError() { @@ -134,7 +134,7 @@ export function ReportingPageProvider({ getService, getPageObjects }) { } async getGenerateReportButton() { - return await retry.try(() => testSubjects.find('generateReportButton')); + return await retry.try(async () => await testSubjects.find('generateReportButton')); } async checkUsePrintLayout() { @@ -146,16 +146,20 @@ export function ReportingPageProvider({ getService, getPageObjects }) { } async clickGenerateReportButton() { - await retry.try(() => testSubjects.click('generateReportButton')); + await testSubjects.click('generateReportButton'); } async checkForReportingToasts() { log.debug('Reporting:checkForReportingToasts'); const isToastPresent = await testSubjects.exists('completeReportSuccess', { - timeout: 60000 + allowHidden: true, + timeout: 90000 }); // Close toast so it doesn't obscure the UI. - await testSubjects.click('completeReportSuccess toastCloseButton'); + if (isToastPresent) { + await testSubjects.click('completeReportSuccess toastCloseButton'); + } + return isToastPresent; } diff --git a/x-pack/test/functional/services/browser_exec_scripts/read_pipeline_list_rows.js b/x-pack/test/functional/services/browser_exec_scripts/read_pipeline_list_rows.js deleted file mode 100644 index 078592a448d0e..0000000000000 --- a/x-pack/test/functional/services/browser_exec_scripts/read_pipeline_list_rows.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export function readPipelineListRows(container, cssSelectors) { - return Array.prototype.map.call( - container.querySelectorAll(cssSelectors.ROW), - function (row) { - return { - selected: row.querySelector('input[type=checkbox]').checked, - id: row.querySelector(cssSelectors.CELL_ID).innerText.trim(), - description: row.querySelector(cssSelectors.CELL_DESCRIPTION).innerText.trim(), - lastModified: row.querySelector(cssSelectors.CELL_LAST_MODIFIED).innerText.trim(), - username: row.querySelector(cssSelectors.CELL_USERNAME).innerText.trim(), - }; - } - ); -} diff --git a/x-pack/test/functional/services/pipeline_list.js b/x-pack/test/functional/services/pipeline_list.js index 1e5a3bcc630cc..1a0cf3f5c6046 100644 --- a/x-pack/test/functional/services/pipeline_list.js +++ b/x-pack/test/functional/services/pipeline_list.js @@ -4,12 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { readPipelineListRows } from './browser_exec_scripts/read_pipeline_list_rows'; - export function PipelineListProvider({ getService }) { const testSubjects = getService('testSubjects'); const retry = getService('retry'); - const browser = getService('browser'); const random = getService('random'); // test subject selectors @@ -113,17 +110,17 @@ export function PipelineListProvider({ getService }) { * @return {Promise>} */ async readRows() { - return await browser.execute( - readPipelineListRows, - await testSubjects.find(SUBJ_CONTAINER), - { - ROW: testSubjects.getCssSelector(INNER_SUBJ_ROW), - CELL_ID: testSubjects.getCssSelector(INNER_SUBJ_CELL_ID), - CELL_DESCRIPTION: testSubjects.getCssSelector(INNER_SUBJ_CELL_DESCRIPTION), - CELL_LAST_MODIFIED: testSubjects.getCssSelector(INNER_SUBJ_CELL_LAST_MODIFIED), - CELL_USERNAME: testSubjects.getCssSelector(INNER_SUBJ_CELL_USERNAME), - }, - ); + const pipelineTable = await testSubjects.find('pipelineTable'); + const $ = await pipelineTable.parseDomContent(); + return $.findTestSubjects(INNER_SUBJ_ROW).toArray().map(row => { + return { + selected: $(row).hasClass('euiTableRow-isSelected'), + id: $(row).findTestSubjects(INNER_SUBJ_CELL_ID).text(), + description: $(row).findTestSubjects(INNER_SUBJ_CELL_DESCRIPTION).text(), + lastModified: $(row).findTestSubjects(INNER_SUBJ_CELL_LAST_MODIFIED).text(), + username: $(row).findTestSubjects(INNER_SUBJ_CELL_USERNAME).text() + }; + }); } /** @@ -163,9 +160,11 @@ export function PipelineListProvider({ getService }) { * @return {Promise} */ async assertExists() { - await retry.waitFor('pipline list visible on screen', async () => ( - await testSubjects.exists(SUBJ_CONTAINER) - )); + await retry.waitFor('pipline list visible on screen', async () => { + const container = await testSubjects.find(SUBJ_CONTAINER); + const found = await container.findAllByCssSelector('table tbody'); + return found.length > 0; + }); } /** diff --git a/x-pack/test/reporting/functional/reporting.js b/x-pack/test/reporting/functional/reporting.js index 1e3ccea64e218..33f064388aa6c 100644 --- a/x-pack/test/reporting/functional/reporting.js +++ b/x-pack/test/reporting/functional/reporting.js @@ -299,7 +299,7 @@ export default function ({ getService, getPageObjects }) { await PageObjects.visualize.clickBucket('X-Axis'); await PageObjects.visualize.selectAggregation('Date Histogram'); await PageObjects.visualize.clickGo(); - await PageObjects.visualize.saveVisualizationExpectSuccess('my viz'); + await PageObjects.visualize.saveVisualization('my viz'); await PageObjects.reporting.openPdfReportingPanel(); await expectEnabledGenerateReportButton(); }); diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 87e34dc754cdc..2e9fc43a6aa62 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -2,13 +2,13 @@ "extends": "../tsconfig.json", "compilerOptions": { "types": [ - "expect.js", + "@kbn/test/types/expect.js", "mocha", "node" ] }, "include": [ - "**/*", + "**/*" ], "exclude": [], } diff --git a/x-pack/test/types/providers.ts b/x-pack/test/types/providers.ts index 6865fece8605a..9699775428a5c 100644 --- a/x-pack/test/types/providers.ts +++ b/x-pack/test/types/providers.ts @@ -4,14 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -export interface EsArchiverOptions { - skipExisting?: boolean; -} - -export interface EsArchiver { - load(archiveName: string, options?: EsArchiverOptions): Promise; - unload(archiveName: string): Promise; -} +import { EsArchiver } from '../../../src/es_archiver'; export interface KibanaFunctionalTestDefaultProviders { getService(serviceName: 'esArchiver'): EsArchiver; diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 31ec11765e13a..c74d60e902326 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -11,6 +11,7 @@ "test/**/*" ], "compilerOptions": { + "outDir": ".", "paths": { "ui/*": [ "src/legacy/ui/public/*" @@ -30,7 +31,8 @@ }, "types": [ "node", - "jest" + "jest", + "@kbn/test/types/expect.js" ] } } diff --git a/yarn.lock b/yarn.lock index 06b333002f14c..66bcb927ce990 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35,56 +35,34 @@ esutils "^2.0.2" js-tokens "^3.0.0" -"@babel/core@^7.2.2": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687" - integrity sha512-59vB0RWt09cAct5EIe58+NzGP4TFSD3Bz//2/ELy3ZeTeKF6VTD1AXlH8BGGbCX0PuobZBsIzO7IAI9PH67eKw== +"@babel/core@^7.1.0", "@babel/core@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b" + integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.2.2" + "@babel/generator" "^7.3.4" "@babel/helpers" "^7.2.0" - "@babel/parser" "^7.2.2" + "@babel/parser" "^7.3.4" "@babel/template" "^7.2.2" - "@babel/traverse" "^7.2.2" - "@babel/types" "^7.2.2" + "@babel/traverse" "^7.3.4" + "@babel/types" "^7.3.4" convert-source-map "^1.1.0" debug "^4.1.0" json5 "^2.1.0" - lodash "^4.17.10" + lodash "^4.17.11" resolve "^1.3.2" semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0.tgz#1efd58bffa951dc846449e58ce3a1d7f02d393aa" - integrity sha512-/BM2vupkpbZXq22l1ALO7MqXJZH2k8bKVv8Y+pABFnzWdztDB/ZLveP5At21vLz5c2YtSE6p7j2FZEsqafMz5Q== +"@babel/generator@^7.0.0", "@babel/generator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e" + integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.3.4" jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.3.tgz#2103ec9c42d9bdad9190a6ad5ff2d456fd7b8673" - integrity sha512-ZoCZGcfIJFJuZBqxcY9OjC1KW2lWK64qrX1o4UYL3yshVhwKFYgzpWZ0vvtGMNJdTlvkw0W+HR1VnYN8q3QPFQ== - dependencies: - "@babel/types" "^7.1.3" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.2.2": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.0.tgz#f663838cd7b542366de3aa608a657b8ccb2a99eb" - integrity sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg== - dependencies: - "@babel/types" "^7.3.0" - jsesc "^2.5.1" - lodash "^4.17.10" + lodash "^4.17.11" source-map "^0.5.0" trim-right "^1.0.1" @@ -104,11 +82,11 @@ "@babel/types" "^7.0.0" "@babel/helper-builder-react-jsx@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.0.0.tgz#fa154cb53eb918cf2a9a7ce928e29eb649c5acdb" - integrity sha512-ebJ2JM6NAKW0fQEqN8hOLxK84RbRz9OkUhGS/Xd5u56ejMfVbayJ4+LykERZCOUM6faa6Fp3SZNX3fcT16MKHw== + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz#a1ac95a5d2b3e88ae5e54846bf462eeb81b318a4" + integrity sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.3.0" esutils "^2.0.0" "@babel/helper-call-delegate@^7.1.0": @@ -120,16 +98,17 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-create-class-features-plugin@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.0.tgz#2b01a81b3adc2b1287f9ee193688ef8dc71e718f" - integrity sha512-DUsQNS2CGLZZ7I3W3fvh0YpPDd6BuWJlDl+qmZZpABZHza2ErE3LxtEzLJFHFC1ZwtlAXvHhbFYbtM5o5B0WBw== +"@babel/helper-create-class-features-plugin@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.4.tgz#092711a7a3ad8ea34de3e541644c2ce6af1f6f0c" + integrity sha512-uFpzw6L2omjibjxa8VGZsJUPL5wJH0zzGKpoz0ccBkzIa6C8kWNUbiBmQ0rgOKWlHJ6qzmfa6lTiGchiV8SC+g== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-member-expression-to-functions" "^7.0.0" "@babel/helper-optimise-call-expression" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.2.3" + "@babel/helper-replace-supers" "^7.3.4" + "@babel/helper-split-export-declaration" "^7.0.0" "@babel/helper-define-map@^7.1.0": version "7.1.0" @@ -186,15 +165,15 @@ "@babel/types" "^7.0.0" "@babel/helper-module-transforms@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz#470d4f9676d9fad50b324cdcce5fbabbc3da5787" - integrity sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw== + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz#ab2f8e8d231409f8370c883d20c335190284b963" + integrity sha512-YRD7I6Wsv+IHuTPkAmAS4HhY0dkPobgLftHp0cRGZSdrRvmZY8rFvae/GVu3bD00qscuvK3WPHB3YdNpBXUqrA== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/template" "^7.2.2" + "@babel/types" "^7.2.2" lodash "^4.17.10" "@babel/helper-optimise-call-expression@^7.0.0": @@ -227,25 +206,15 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-replace-supers@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz#5fc31de522ec0ef0899dc9b3e7cf6a5dd655f362" - integrity sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.0.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-replace-supers@^7.2.3": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz#19970020cf22677d62b3a689561dbd9644d8c5e5" - integrity sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA== +"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz#a795208e9b911a6eeb08e5891faacf06e7013e13" + integrity sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A== dependencies: "@babel/helper-member-expression-to-functions" "^7.0.0" "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.2.3" - "@babel/types" "^7.0.0" + "@babel/traverse" "^7.3.4" + "@babel/types" "^7.3.4" "@babel/helper-simple-access@^7.1.0": version "7.1.0" @@ -263,14 +232,14 @@ "@babel/types" "^7.0.0" "@babel/helper-wrap-function@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz#8cf54e9190706067f016af8f75cb3df829cc8c66" - integrity sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA== + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" + integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/template" "^7.1.0" "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/types" "^7.2.0" "@babel/helpers@^7.2.0": version "7.3.1" @@ -290,20 +259,10 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.0.tgz#a7cd42cb3c12aec52e24375189a47b39759b783e" - integrity sha512-SmjnXCuPAlai75AFtzv+KCBcJ3sDDWbIn+WytKw1k+wAtEy6phqI2RqKh/zAnw53i1NR8su3Ep/UoqaKcimuLg== - -"@babel/parser@^7.1.3": - version "7.1.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.6.tgz#16e97aca1ec1062324a01c5a6a7d0df8dd189854" - integrity sha512-dWP6LJm9nKT6ALaa+bnL247GHHMWir3vSlZ2+IHgHgktZQx0L3Uvq2uAWcuzIe+fujRsYWBW2q622C5UvGK9iQ== - -"@babel/parser@^7.2.2", "@babel/parser@^7.2.3": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.1.tgz#8f4ffd45f779e6132780835ffa7a215fa0b2d181" - integrity sha512-ATz6yX/L8LEnC3dtLQnIx4ydcPxhLcoy9Vl6re00zb2w5lG6itY6Vhnr1KFRPq/FHNsgl/gh2mjNN20f9iJTTA== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.3", "@babel/parser@^7.2.2", "@babel/parser@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c" + integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ== "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" @@ -314,12 +273,12 @@ "@babel/helper-remap-async-to-generator" "^7.1.0" "@babel/plugin-syntax-async-generators" "^7.2.0" -"@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz#272636bc0fa19a0bc46e601ec78136a173ea36cd" - integrity sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg== +"@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.4.tgz#410f5173b3dc45939f9ab30ca26684d72901405e" + integrity sha512-lUf8D3HLs4yYlAo8zjuneLvfxN7qfKv1Yzbj5vjqaqMJxgJA3Ipwp4VUJ+OrOdz53Wbww6ahwB8UhB2HQyLotA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.3.0" + "@babel/helper-create-class-features-plugin" "^7.3.4" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-json-strings@^7.2.0": @@ -330,10 +289,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.1.tgz#f69fb6a1ea6a4e1c503994a91d9cf76f3c4b36e8" - integrity sha512-Nmmv1+3LqxJu/V5jU9vJmxR/KIRWFk2qLHmbB56yRRRFhlaSuOVXscX3gUmhaKgUhzA3otOHVubbIEVYsZ0eZg== +"@babel/plugin-proposal-object-rest-spread@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz#47f73cf7f2a721aad5c0261205405c642e424654" + integrity sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" @@ -383,7 +342,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-object-rest-spread@^7.2.0": +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== @@ -397,10 +356,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-typescript@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.0.0.tgz#90f4fe0a741ae9c0dcdc3017717c05a0cbbd5158" - integrity sha512-5fxmdqiAQVQTIS+KSvYeZuTt91wKtBTYi6JlIkvbQ6hmO+9fZE81ezxmMiFMIsxE7CdRSgzn7nQ1BChcvK9OpA== +"@babel/plugin-syntax-typescript@^7.2.0": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" + integrity sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -411,10 +370,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-async-to-generator@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz#68b8a438663e88519e65b776f8938f3445b1a2ff" - integrity sha512-CEHzg4g5UraReozI9D4fblBYABs7IM6UerAVG7EJVrTLC5keh00aEuLUT+O40+mJCEzaXkYfTCUKIyeDfMOFFQ== +"@babel/plugin-transform-async-to-generator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz#4e45408d3c3da231c0e7b823f407a53a7eb3048c" + integrity sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -427,25 +386,25 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-block-scoping@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz#f17c49d91eedbcdf5dd50597d16f5f2f770132d4" - integrity sha512-vDTgf19ZEV6mx35yiPJe4fS02mPQUUcBNwWQSZFXSzTSbsJFQvHt7DqyS3LK8oOWALFOsJ+8bbqBgkirZteD5Q== +"@babel/plugin-transform-block-scoping@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz#5c22c339de234076eee96c8783b2fed61202c5c4" + integrity sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.10" + lodash "^4.17.11" -"@babel/plugin-transform-classes@^7.2.0": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.2.tgz#6c90542f210ee975aa2aa8c8b5af7fa73a126953" - integrity sha512-gEZvgTy1VtcDOaQty1l10T3jQmJKlNVxLDCs+3rCVPr6nMkODLELxViq5X9l+rfxbie3XrfrMCYYY6eX3aOcOQ== +"@babel/plugin-transform-classes@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz#dc173cb999c6c5297e0b5f2277fdaaec3739d0cc" + integrity sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-define-map" "^7.1.0" "@babel/helper-function-name" "^7.1.0" "@babel/helper-optimise-call-expression" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.1.0" + "@babel/helper-replace-supers" "^7.3.4" "@babel/helper-split-export-declaration" "^7.0.0" globals "^11.1.0" @@ -534,10 +493,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" -"@babel/plugin-transform-modules-systemjs@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.2.0.tgz#912bfe9e5ff982924c81d0937c92d24994bb9068" - integrity sha512-aYJwpAhoK9a+1+O625WIjvMY11wkB/ok0WClVwmeo3mCjcNRjt+/8gHWrB5i+00mUju0gWsBkQnPpdvQ7PImmQ== +"@babel/plugin-transform-modules-systemjs@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz#813b34cd9acb6ba70a84939f3680be0eb2e58861" + integrity sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw== dependencies: "@babel/helper-hoist-variables" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -620,6 +579,13 @@ dependencies: regenerator-transform "^0.13.3" +"@babel/plugin-transform-regenerator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz#1601655c362f5b38eead6a52631f5106b29fa46a" + integrity sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA== + dependencies: + regenerator-transform "^0.13.4" + "@babel/plugin-transform-runtime@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.1.0.tgz#9f76920d42551bb577e2dc594df229b5f7624b63" @@ -667,13 +633,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-typescript@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.1.0.tgz#81e7b4be90e7317cbd04bf1163ebf06b2adee60b" - integrity sha512-TOTtVeT+fekAesiCHnPz+PSkYSdOSLyLn42DI45nxg6iCdlQY6LIj/tYqpMB0y+YicoTUiYiXqF8rG6SKfhw6Q== +"@babel/plugin-transform-typescript@^7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.3.2.tgz#59a7227163e55738842f043d9e5bd7c040447d96" + integrity sha512-Pvco0x0ZSCnexJnshMfaibQ5hnK8aUHSvjCQhC1JR8eeg+iBwt0AtCO7gWxJ358zZevuf9wPSO5rv+WJcbHPXQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-typescript" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.2.0" "@babel/plugin-transform-unicode-regex@^7.2.0": version "7.2.0" @@ -684,16 +650,16 @@ "@babel/helper-regex" "^7.0.0" regexpu-core "^4.1.3" -"@babel/preset-env@^7.1.0", "@babel/preset-env@^7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.1.tgz#389e8ca6b17ae67aaf9a2111665030be923515db" - integrity sha512-FHKrD6Dxf30e8xgHQO0zJZpUPfVZg+Xwgz5/RdSWCbza9QLNk4Qbp40ctRoqDxml3O8RMzB1DU55SXeDG6PqHQ== +"@babel/preset-env@^7.1.0", "@babel/preset-env@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.4.tgz#887cf38b6d23c82f19b5135298bdb160062e33e1" + integrity sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-async-generator-functions" "^7.2.0" "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.3.1" + "@babel/plugin-proposal-object-rest-spread" "^7.3.4" "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" "@babel/plugin-proposal-unicode-property-regex" "^7.2.0" "@babel/plugin-syntax-async-generators" "^7.2.0" @@ -701,10 +667,10 @@ "@babel/plugin-syntax-object-rest-spread" "^7.2.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.3.4" "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.2.0" - "@babel/plugin-transform-classes" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.3.4" + "@babel/plugin-transform-classes" "^7.3.4" "@babel/plugin-transform-computed-properties" "^7.2.0" "@babel/plugin-transform-destructuring" "^7.2.0" "@babel/plugin-transform-dotall-regex" "^7.2.0" @@ -715,13 +681,13 @@ "@babel/plugin-transform-literals" "^7.2.0" "@babel/plugin-transform-modules-amd" "^7.2.0" "@babel/plugin-transform-modules-commonjs" "^7.2.0" - "@babel/plugin-transform-modules-systemjs" "^7.2.0" + "@babel/plugin-transform-modules-systemjs" "^7.3.4" "@babel/plugin-transform-modules-umd" "^7.2.0" "@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0" "@babel/plugin-transform-new-target" "^7.0.0" "@babel/plugin-transform-object-super" "^7.2.0" "@babel/plugin-transform-parameters" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.0.0" + "@babel/plugin-transform-regenerator" "^7.3.4" "@babel/plugin-transform-shorthand-properties" "^7.2.0" "@babel/plugin-transform-spread" "^7.2.0" "@babel/plugin-transform-sticky-regex" "^7.2.0" @@ -752,13 +718,13 @@ "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" -"@babel/preset-typescript@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.1.0.tgz#49ad6e2084ff0bfb5f1f7fb3b5e76c434d442c7f" - integrity sha512-LYveByuF9AOM8WrsNne5+N79k1YxjNB6gmpCQsnuSBAcV8QUeB+ZUxQzL7Rz7HksPbahymKkq2qBR+o36ggFZA== +"@babel/preset-typescript@^7.3.3": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz#88669911053fa16b2b276ea2ede2ca603b3f307a" + integrity sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.1.0" + "@babel/plugin-transform-typescript" "^7.3.2" "@babel/runtime@7.0.0-beta.54": version "7.0.0-beta.54" @@ -775,16 +741,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/template@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.0.tgz#58cc9572e1bfe24fe1537fdf99d839d53e517e22" - integrity sha512-yZ948B/pJrwWGY6VxG6XRFsVTee3IQ7bihq9zFpM00Vydu6z5Xwg0C3J644kxI9WOTzd+62xcIsQ+AT1MGhqhA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/template@^7.1.2", "@babel/template@^7.2.2": +"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== @@ -793,76 +750,28 @@ "@babel/parser" "^7.2.2" "@babel/types" "^7.2.2" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.0.tgz#503ec6669387efd182c3888c4eec07bcc45d91b2" - integrity sha512-bwgln0FsMoxm3pLOgrrnGaXk18sSM9JNf1/nHC/FksmNGFbYnPWY4GYCfLxyP1KRmfsxqkRpfoa6xr6VuuSxdw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.0.0" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - debug "^3.1.0" - globals "^11.1.0" - lodash "^4.17.10" - -"@babel/traverse@^7.1.4": - version "7.1.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.4.tgz#f4f83b93d649b4b2c91121a9087fa2fa949ec2b4" - integrity sha512-my9mdrAIGdDiSVBuMjpn/oXYpva0/EZwWL3sm3Wcy/AVWO2eXnsoZruOT9jOGNRXU8KbCIu5zsKnXcAJ6PcV6Q== +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06" + integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.3" + "@babel/generator" "^7.3.4" "@babel/helper-function-name" "^7.1.0" "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.1.3" - "@babel/types" "^7.1.3" - debug "^3.1.0" - globals "^11.1.0" - lodash "^4.17.10" - -"@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" - integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.2.2" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.2.3" - "@babel/types" "^7.2.2" + "@babel/parser" "^7.3.4" + "@babel/types" "^7.3.4" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.10" - -"@babel/types@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0.tgz#6e191793d3c854d19c6749989e3bc55f0e962118" - integrity sha512-5tPDap4bGKTLPtci2SUl/B7Gv8RnuJFuQoWx26RJobS0fFrz4reUA3JnwIM+HVHEmWE0C1mzKhDtTp8NsWY02Q== - dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" - -"@babel/types@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.3.tgz#3a767004567060c2f40fca49a304712c525ee37d" - integrity sha512-RpPOVfK+yatXyn8n4PB1NW6k9qjinrXrRR8ugBN8fD6hCy5RXI6PSbVqpOJBO9oSaY7Nom4ohj35feb0UR9hSA== - dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" + lodash "^4.17.11" -"@babel/types@^7.2.2", "@babel/types@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.0.tgz#61dc0b336a93badc02bf5f69c4cd8e1353f2ffc0" - integrity sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw== +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed" + integrity sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ== dependencies: esutils "^2.0.2" - lodash "^4.17.10" + lodash "^4.17.11" to-fast-properties "^2.0.0" "@elastic/eui@0.0.23": @@ -1734,7 +1643,7 @@ resolved "https://registry.yarnpkg.com/@types/chance/-/chance-1.0.1.tgz#c10703020369602c40dd9428cc6e1437027116df" integrity sha512-jtV6Bv/j+xk4gcXeLlESwNc/m/I/dIZA0xrt29g0uKcjyPob8iisj/5z0ARE+Ldfx4MxjNFNECG0z++J7zJgqg== -"@types/cheerio@*": +"@types/cheerio@*", "@types/cheerio@^0.22.10": version "0.22.10" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.10.tgz#780d552467824be4a241b29510a7873a7432c4a6" integrity sha512-fOM/Jhv51iyugY7KOBZz2ThfT1gwvsGCfWxpLpZDgkGjpEO4Le9cld07OdskikLjDUQJ43dzDaVRSFwQlpdqVg== @@ -1803,10 +1712,10 @@ dependencies: "@types/d3-time" "*" -"@types/d3-shape@^1.2.2": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.2.3.tgz#cadc9f93a626db9190f306048a650df4ffa4e500" - integrity sha512-iP9TcX0EVi+LlX+jK9ceS+yhEz5abTitF+JaO2ugpRE/J+bccaYLe/0/3LETMmdaEkYarIyboZW8OF67Mpnj1w== +"@types/d3-shape@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.3.1.tgz#1b4f92b7efd7306fe2474dc6ee94c0f0ed2e6ab6" + integrity sha512-usqdvUvPJ7AJNwpd2drOzRKs1ELie53p2m2GnPKr076/ADM579jVTJ5dPsoZ5E/CMNWk8lvPWYQSvilpp6jjwg== dependencies: "@types/d3-path" "*" @@ -1892,11 +1801,6 @@ dependencies: "@types/node" "*" -"@types/expect.js@^0.3.29": - version "0.3.29" - resolved "https://registry.yarnpkg.com/@types/expect.js/-/expect.js-0.3.29.tgz#28dd359155b84b8ecb094afc3f4b74c3222dca3b" - integrity sha1-KN01kVW4S47LCUr8P0t0wyItyjs= - "@types/fetch-mock@7.2.1": version "7.2.1" resolved "https://registry.yarnpkg.com/@types/fetch-mock/-/fetch-mock-7.2.1.tgz#5630999aa75532e00af42a54cbe05e1651f4a080" @@ -2016,10 +1920,17 @@ dependencies: "@types/node" "*" -"@types/jest@^23.3.1": - version "23.3.9" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.3.9.tgz#c16b55186ee73ae65e001fbee69d392c51337ad1" - integrity sha512-wNMwXSUcwyYajtbayfPp55tSayuDVU6PfY5gzvRSj80UvxdXEJOVPnUVajaOp7NgXLm+1e2ZDLULmpsU9vDvQw== +"@types/jest-diff@*": + version "20.0.1" + resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89" + integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA== + +"@types/jest@^24.0.9": + version "24.0.9" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.9.tgz#74ce9cf337f25e189aa18f76ab3d65e8669b55f2" + integrity sha512-k3OOeevcBYLR5pdsOv5g3OP94h3mrJmLPHFEPWgbbVy2tGv0TZ/TlygiC848ogXhK8NL0I5up7YYtwpCp8xCJA== + dependencies: + "@types/jest-diff" "*" "@types/joi@*", "@types/joi@^13.4.2": version "13.6.1" @@ -2046,11 +1957,6 @@ resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.0.32.tgz#121f6917c4389db3923640b2e68de5fa64dda88e" integrity sha512-q9Q6+eUEGwQkv4Sbst3J4PNgDOvpuVuKj79Hl/qnmBMEIPzB5QoFRUtjcgcg2xNUZyYUGXBk5wYIBKHt0A+Mxw== -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - "@types/json5@^0.0.30": version "0.0.30" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818" @@ -2167,10 +2073,10 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@10.12.12", "@types/node@>=6.0.0", "@types/node@^10.12.12": - version "10.12.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.12.tgz#e15a9d034d9210f00320ef718a50c4a799417c47" - integrity sha512-Pr+6JRiKkfsFvmU/LK68oBRCQeEg36TyAbPhc2xpez24OOZZCuoIhWGTd39VZy6nGafSbxzGouFPTFD/rR1A0A== +"@types/node@*", "@types/node@10.12.27", "@types/node@>=6.0.0", "@types/node@^10.12.27": + version "10.12.27" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.27.tgz#eb3843f15d0ba0986cc7e4d734d2ee8b50709ef8" + integrity sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg== "@types/normalize-package-data@*": version "2.4.0" @@ -3193,6 +3099,11 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" @@ -3402,12 +3313,12 @@ append-buffer@^1.0.2: dependencies: buffer-equal "^1.0.0" -append-transform@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" - integrity sha1-126/jKlNJ24keja61EpLdKthGZE= +append-transform@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" + integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw== dependencies: - default-require-extensions "^1.0.0" + default-require-extensions "^2.0.0" aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" @@ -3759,7 +3670,7 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== -async-each@^1.0.0: +async-each@^1.0.0, async-each@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" integrity sha1-GdOGodntxufByF04iu28xW0zYC0= @@ -3922,15 +3833,6 @@ autoprefixer@^9.3.1: postcss "^7.0.5" postcss-value-parser "^3.3.1" -aws-sdk@2.2.33: - version "2.2.33" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.2.33.tgz#99f154549473b5c166df86473693c5a9dc57a33e" - integrity sha1-mfFUVJRztcFm34ZHNpPFqdxXoz4= - dependencies: - sax "0.5.3" - xml2js "0.2.8" - xmlbuilder "0.4.2" - aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -4022,7 +3924,7 @@ babel-core@6.26.3, babel-core@^6.26.3: slash "^1.0.0" source-map "^0.5.7" -babel-core@^6.0.0, babel-core@^6.26.0: +babel-core@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" integrity sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g= @@ -4252,6 +4154,16 @@ babel-jest@^23.6.0: babel-plugin-istanbul "^4.1.6" babel-preset-jest "^23.2.0" +babel-jest@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.1.0.tgz#441e23ef75ded3bd547e300ac3194cef87b55190" + integrity sha512-MLcagnVrO9ybQGLEfZUqnOzv36iQzU7Bj4elm39vCukumLVSfoX+tRy3/jW7lUKc7XdpRmB/jech6L/UCsSZjw== + dependencies: + babel-plugin-istanbul "^5.1.0" + babel-preset-jest "^24.1.0" + chalk "^2.4.2" + slash "^2.0.0" + babel-loader@7.1.5, babel-loader@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.5.tgz#e3ee0cd7394aa557e013b02d3e492bfd07aa6d68" @@ -4302,11 +4214,25 @@ babel-plugin-istanbul@^4.1.6: istanbul-lib-instrument "^1.10.1" test-exclude "^4.2.1" +babel-plugin-istanbul@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz#7981590f1956d75d67630ba46f0c22493588c893" + integrity sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ== + dependencies: + find-up "^3.0.0" + istanbul-lib-instrument "^3.0.0" + test-exclude "^5.0.0" + babel-plugin-jest-hoist@^23.2.0: version "23.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" integrity sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc= +babel-plugin-jest-hoist@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.1.0.tgz#dfecc491fb15e2668abbd690a697a8fd1411a7f8" + integrity sha512-gljYrZz8w1b6fJzKcsfKsipSru2DU2DmQ39aB6nV3xQ0DDv3zpIzKGortA5gknrhNnPN8DweaEgrnZdmbGmhnw== + babel-plugin-macros@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.4.2.tgz#21b1a2e82e2130403c5ff785cba6548e9b644b28" @@ -4475,12 +4401,12 @@ babel-plugin-transform-class-properties@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-define@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.0.tgz#94c5f9459c810c738cc7c50cbd44a31829d6f319" - integrity sha1-lMX5RZyBDHOMx8UMvUSjGCnW8xk= +babel-plugin-transform-define@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.1.tgz#b21b7bad3b84cf8e3f07cdc8c660b99cbbc01213" + integrity sha512-JXZ1xE9jIbKCGYZ4wbSMPSI5mdS4DRLi5+SkTHgZqWn5YIf/EucykkzUsPmzJlpkX8fsMVdLnA5vt/LvT97Zbg== dependencies: - lodash "4.17.4" + lodash "^4.17.11" traverse "0.6.6" babel-plugin-transform-es2015-arrow-functions@^6.22.0: @@ -4915,6 +4841,14 @@ babel-preset-jest@^23.2.0: babel-plugin-jest-hoist "^23.2.0" babel-plugin-syntax-object-rest-spread "^6.13.0" +babel-preset-jest@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.1.0.tgz#83bc564fdcd4903641af65ec63f2f5de6b04132e" + integrity sha512-FfNLDxFWsNX9lUmtwY7NheGlANnagvxq8LZdl5PKnVG3umP+S/g0XbVBfwtA4Ai3Ri/IMkWabBz3Tyk9wdspcw== + dependencies: + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + babel-plugin-jest-hoist "^24.1.0" + babel-preset-minify@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.0.tgz#e25bb8d3590087af02b650967159a77c19bfb96b" @@ -5004,7 +4938,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= @@ -5038,6 +4972,13 @@ babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24. lodash "^4.17.4" to-fast-properties "^1.0.3" +"babel7-plugin-add-module-exports@npm:babel-plugin-add-module-exports@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.0.tgz#72b5424d941a336c6a35357f373d8b8366263031" + integrity sha512-m0sMxPL4FaN2K69GQgaRJa4Ny15qKSdoknIcpN+gz+NaJlAW9pge/povs13tPYsKDboflrEQC+/3kfIsONBTaw== + optionalDependencies: + chokidar "^2.0.4" + babylon@7.0.0-beta.47: version "7.0.0-beta.47" resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.47.tgz#6d1fa44f0abec41ab7c780481e62fd9aafbdea80" @@ -5430,35 +5371,16 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -braces@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.0.tgz#a46941cb5fb492156b3d6a656e06c35364e3e66e" - integrity sha512-P4O8UQRdGiMLWSizsApmXVQDBS6KCt7dSexgLKBmH5Hr1CZq7vsnscFh8oR1sP1ab1Zj0uCHCEzZeV6SfUf3rA== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - define-property "^1.0.0" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" - integrity sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ== +braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" - define-property "^1.0.0" extend-shallow "^2.0.1" fill-range "^4.0.0" isobject "^3.0.1" - kind-of "^6.0.2" repeat-element "^1.1.2" snapdragon "^0.8.1" snapdragon-node "^2.0.1" @@ -5904,6 +5826,11 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= +callsites@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" + integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== + camel-case@3.0.x, camel-case@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" @@ -6113,7 +6040,7 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^5.2.0" -chalk@^2.3.2, chalk@~2.4.1: +chalk@^2.3.2, chalk@^2.4.2, chalk@~2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -6277,44 +6204,24 @@ chokidar@^1.6.1: optionalDependencies: fsevents "^1.0.0" -chokidar@^2.0.0, chokidar@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" - integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.0" - braces "^2.3.0" - glob-parent "^3.1.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - lodash.debounce "^4.0.8" - normalize-path "^2.1.1" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - upath "^1.0.5" - optionalDependencies: - fsevents "^1.2.2" - -chokidar@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.2.tgz#4dc65139eeb2714977735b6a35d06e97b494dfd7" - integrity sha512-l32Hw3wqB0L2kGVmSbK/a+xXLDrUEsc84pSgMkmwygHvD7ubRsP/vxxHa5BtB6oix1XLLVCHyYMsckRXxThmZw== +chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4: + version "2.1.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.2.tgz#9c23ea40b01638439e0513864d362aeacc5ad058" + integrity sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg== dependencies: anymatch "^2.0.0" - async-each "^1.0.0" - braces "^2.3.0" + async-each "^1.0.1" + braces "^2.3.2" glob-parent "^3.1.0" - inherits "^2.0.1" + inherits "^2.0.3" is-binary-path "^1.0.0" is-glob "^4.0.0" - normalize-path "^2.1.1" + normalize-path "^3.0.0" path-is-absolute "^1.0.0" - readdirp "^2.0.0" - upath "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.0" optionalDependencies: - fsevents "^1.0.0" + fsevents "^1.2.7" chownr@^1.0.1: version "1.0.1" @@ -6354,6 +6261,11 @@ ci-info@^1.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4" integrity sha512-uTGIPNx/nSpBdsF6xnseRXLLtfr9VLqkz8ZqHXr3Y7b6SftyRxBGjwMtJj1OhNbmlc1wZzLNAlAcvyIiE8a6ZA== +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -6836,6 +6748,11 @@ compare-versions@3.1.0: resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.1.0.tgz#43310256a5c555aaed4193c04d8f154cf9c6efd5" integrity sha512-4hAxDSBypT/yp2ySFD346So6Ragw5xmBn/e/agIGl3bZr6DLUqnoRZPusxKrXdYRZpgexO9daejmIenlq/wrIQ== +compare-versions@^3.2.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26" + integrity sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg== + component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -7185,6 +7102,11 @@ core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" integrity sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4= +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -7957,7 +7879,7 @@ debug@3.X, debug@^3.1.0, debug@^3.2.5: dependencies: ms "^2.1.1" -debug@^4.1.0: +debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -8078,7 +8000,7 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -deepmerge@2.2.1, deepmerge@^2.0.1: +deepmerge@2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== @@ -8091,12 +8013,12 @@ default-gateway@^2.6.0: execa "^0.10.0" ip-regex "^2.1.0" -default-require-extensions@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" - integrity sha1-836hXT4T/9m0N9M+GnW1+5eHTLg= +default-require-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" + integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc= dependencies: - strip-bom "^2.0.0" + strip-bom "^3.0.0" default-uid@^1.0.0: version "1.0.0" @@ -8311,6 +8233,11 @@ diagnostics@^1.1.1: enabled "1.0.x" kuler "1.0.x" +diff-sequences@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.0.0.tgz#cdf8e27ed20d8b8d3caccb4e0c0d8fe31a173013" + integrity sha512-46OkIuVGBBnrC0soO/4LHu5LHGHx0uhP65OVz8XOrAJpqiCB2aVIuESvjI1F9oqebuvY8lekS1pt6TN7vt7qsw== + diff@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" @@ -8398,11 +8325,6 @@ doctypes@^1.1.0: resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= -dojo@2.0.0-alpha.7: - version "2.0.0-alpha.7" - resolved "https://registry.yarnpkg.com/dojo/-/dojo-2.0.0-alpha.7.tgz#c2b25d43d8f72ccc9c8fe89a34906a2d271e5c91" - integrity sha1-wrJdQ9j3LMycj+iaNJBqLSceXJE= - dom-converter@~0.2: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -9061,6 +8983,11 @@ es6-promise@^4.0.3, es6-promise@~4.2.4: resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ== +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= + es6-promisify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" @@ -9783,17 +9710,16 @@ expect.js@~0.2.0: resolved "https://registry.yarnpkg.com/expect.js/-/expect.js-0.2.0.tgz#1028533d2c1c363f74a6796ff57ec0520ded2be1" integrity sha1-EChTPSwcNj90pnlv9X7AUg3tK+E= -expect@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-23.6.0.tgz#1e0c8d3ba9a581c87bd71fb9bc8862d443425f98" - integrity sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w== +expect@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-24.1.0.tgz#88e73301c4c785cde5f16da130ab407bdaf8c0f2" + integrity sha512-lVcAPhaYkQcIyMS+F8RVwzbm1jro20IG8OkvxQ6f1JfqhVZyyudCwYogQ7wnktlf14iF3ii7ArIUO/mqvrW9Gw== dependencies: ansi-styles "^3.2.0" - jest-diff "^23.6.0" - jest-get-type "^22.1.0" - jest-matcher-utils "^23.6.0" - jest-message-util "^23.4.0" - jest-regex-util "^23.3.0" + jest-get-type "^24.0.0" + jest-matcher-utils "^24.0.0" + jest-message-util "^24.0.0" + jest-regex-util "^24.0.0" expiry-js@0.1.7: version "0.1.7" @@ -10233,7 +10159,7 @@ filenamify@^2.0.0: strip-outer "^1.0.0" trim-repeated "^1.0.0" -fileset@^2.0.2: +fileset@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= @@ -10702,10 +10628,10 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.0.0, fsevents@^1.2.2, fsevents@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== +fsevents@^1.0.0, fsevents@^1.2.3, fsevents@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" + integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" @@ -11429,7 +11355,7 @@ graceful-fs@^3.0.0: dependencies: natives "^1.1.0" -graceful-fs@^4.1.0, graceful-fs@^4.1.9: +graceful-fs@^4.1.0, graceful-fs@^4.1.15, graceful-fs@^4.1.9: 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== @@ -11903,7 +11829,7 @@ handlebars@4.0.11: optionalDependencies: uglify-js "^2.6" -handlebars@4.0.12, handlebars@^4.0.1, handlebars@^4.0.10, handlebars@^4.0.3: +handlebars@4.0.12, handlebars@^4.0.1, handlebars@^4.0.10: version "4.0.12" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== @@ -11925,6 +11851,17 @@ handlebars@4.0.5: optionalDependencies: uglify-js "^2.6" +handlebars@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" + integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w== + dependencies: + async "^2.5.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" + hapi-auth-cookie@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/hapi-auth-cookie/-/hapi-auth-cookie-9.0.0.tgz#3b0af443334e2bd92490ddb17bed16e3e9edfd01" @@ -12555,6 +12492,11 @@ image-size@~0.5.0: resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + immer@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/immer/-/immer-1.7.2.tgz#a51e9723c50b27e132f6566facbec1c85fc69547" @@ -12592,14 +12534,6 @@ import-lazy@^2.1.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= -import-local@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" - integrity sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ== - dependencies: - pkg-dir "^2.0.0" - resolve-cwd "^2.0.0" - import-local@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" @@ -13082,6 +13016,13 @@ is-ci@^1.0.10: dependencies: ci-info "^1.0.0" +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -13205,10 +13146,10 @@ is-function@^1.0.1, is-function@~1.0.0: resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU= -is-generator-fn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" - integrity sha1-lp1J4bszKfa7fwkIm+JleLLd1Go= +is-generator-fn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.0.0.tgz#038c31b774709641bda678b1f06a4e3227c10b3e" + integrity sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g== is-glob@4.0.0, is-glob@^4.0.0: version "4.0.0" @@ -13603,21 +13544,23 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-api@^1.3.1: - version "1.3.7" - resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.7.tgz#a86c770d2b03e11e3f778cd7aedd82d2722092aa" - integrity sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA== +istanbul-api@^2.0.8: + version "2.1.1" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.1.1.tgz#194b773f6d9cbc99a9258446848b0f988951c4d0" + integrity sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw== dependencies: - async "^2.1.4" - fileset "^2.0.2" - istanbul-lib-coverage "^1.2.1" - istanbul-lib-hook "^1.2.2" - istanbul-lib-instrument "^1.10.2" - istanbul-lib-report "^1.1.5" - istanbul-lib-source-maps "^1.2.6" - istanbul-reports "^1.5.1" - js-yaml "^3.7.0" - mkdirp "^0.5.1" + async "^2.6.1" + compare-versions "^3.2.1" + fileset "^2.0.3" + istanbul-lib-coverage "^2.0.3" + istanbul-lib-hook "^2.0.3" + istanbul-lib-instrument "^3.1.0" + istanbul-lib-report "^2.0.4" + istanbul-lib-source-maps "^3.0.2" + istanbul-reports "^2.1.1" + js-yaml "^3.12.0" + make-dir "^1.3.0" + minimatch "^3.0.4" once "^1.4.0" istanbul-instrumenter-loader@3.0.1: @@ -13635,14 +13578,19 @@ istanbul-lib-coverage@^1.2.0, istanbul-lib-coverage@^1.2.1: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" integrity sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== -istanbul-lib-hook@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz#bc6bf07f12a641fbf1c85391d0daa8f0aea6bf86" - integrity sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw== +istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#0b891e5ad42312c2b9488554f603795f9a2211ba" + integrity sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw== + +istanbul-lib-hook@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz#e0e581e461c611be5d0e5ef31c5f0109759916fb" + integrity sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA== dependencies: - append-transform "^0.4.0" + append-transform "^1.0.0" -istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.10.2: +istanbul-lib-instrument@^1.10.1: version "1.10.2" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca" integrity sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A== @@ -13668,33 +13616,45 @@ istanbul-lib-instrument@^1.7.3: istanbul-lib-coverage "^1.2.0" semver "^5.3.0" -istanbul-lib-report@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz#f2a657fc6282f96170aaf281eb30a458f7f4170c" - integrity sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw== +istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz#a2b5484a7d445f1f311e93190813fa56dfb62971" + integrity sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA== dependencies: - istanbul-lib-coverage "^1.2.1" - mkdirp "^0.5.1" - path-parse "^1.0.5" - supports-color "^3.1.2" + "@babel/generator" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + istanbul-lib-coverage "^2.0.3" + semver "^5.5.0" -istanbul-lib-source-maps@^1.2.4, istanbul-lib-source-maps@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz#37b9ff661580f8fca11232752ee42e08c6675d8f" - integrity sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg== +istanbul-lib-report@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz#bfd324ee0c04f59119cb4f07dab157d09f24d7e4" + integrity sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA== dependencies: - debug "^3.1.0" - istanbul-lib-coverage "^1.2.1" - mkdirp "^0.5.1" - rimraf "^2.6.1" - source-map "^0.5.3" + istanbul-lib-coverage "^2.0.3" + make-dir "^1.3.0" + supports-color "^6.0.0" -istanbul-reports@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.5.1.tgz#97e4dbf3b515e8c484caea15d6524eebd3ff4e1a" - integrity sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw== +istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz#f1e817229a9146e8424a28e5d69ba220fda34156" + integrity sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.3" + make-dir "^1.3.0" + rimraf "^2.6.2" + source-map "^0.6.1" + +istanbul-reports@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.1.1.tgz#72ef16b4ecb9a4a7bd0e2001e00f95d1eec8afa9" + integrity sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw== dependencies: - handlebars "^4.0.3" + handlebars "^4.1.0" istanbul@^0.4.0: version "0.4.5" @@ -13751,74 +13711,78 @@ jade@0.26.3: commander "0.6.1" mkdirp "0.3.0" -jest-changed-files@^23.4.2: - version "23.4.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-23.4.2.tgz#1eed688370cd5eebafe4ae93d34bb3b64968fe83" - integrity sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA== +jest-changed-files@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.0.0.tgz#c02c09a8cc9ca93f513166bc773741bd39898ff7" + integrity sha512-nnuU510R9U+UX0WNb5XFEcsrMqriSiRLeO9KWDFgPrpToaQm60prfQYpxsXigdClpvNot5bekDY440x9dNGnsQ== dependencies: + execa "^1.0.0" throat "^4.0.0" -jest-cli@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-23.6.0.tgz#61ab917744338f443ef2baa282ddffdd658a5da4" - integrity sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ== +jest-cli@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.1.0.tgz#f7cc98995f36e7210cce3cbb12974cbf60940843" + integrity sha512-U/iyWPwOI0T1CIxVLtk/2uviOTJ/OiSWJSe8qt6X1VkbbgP+nrtLJlmT9lPBe4lK78VNFJtrJ7pttcNv/s7yCw== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.1" exit "^0.1.2" glob "^7.1.2" - graceful-fs "^4.1.11" - import-local "^1.0.0" - is-ci "^1.0.10" - istanbul-api "^1.3.1" - istanbul-lib-coverage "^1.2.0" - istanbul-lib-instrument "^1.10.1" - istanbul-lib-source-maps "^1.2.4" - jest-changed-files "^23.4.2" - jest-config "^23.6.0" - jest-environment-jsdom "^23.4.0" - jest-get-type "^22.1.0" - jest-haste-map "^23.6.0" - jest-message-util "^23.4.0" - jest-regex-util "^23.3.0" - jest-resolve-dependencies "^23.6.0" - jest-runner "^23.6.0" - jest-runtime "^23.6.0" - jest-snapshot "^23.6.0" - jest-util "^23.4.0" - jest-validate "^23.6.0" - jest-watcher "^23.4.0" - jest-worker "^23.2.0" - micromatch "^2.3.11" + graceful-fs "^4.1.15" + import-local "^2.0.0" + is-ci "^2.0.0" + istanbul-api "^2.0.8" + istanbul-lib-coverage "^2.0.2" + istanbul-lib-instrument "^3.0.1" + istanbul-lib-source-maps "^3.0.1" + jest-changed-files "^24.0.0" + jest-config "^24.1.0" + jest-environment-jsdom "^24.0.0" + jest-get-type "^24.0.0" + jest-haste-map "^24.0.0" + jest-message-util "^24.0.0" + jest-regex-util "^24.0.0" + jest-resolve-dependencies "^24.1.0" + jest-runner "^24.1.0" + jest-runtime "^24.1.0" + jest-snapshot "^24.1.0" + jest-util "^24.0.0" + jest-validate "^24.0.0" + jest-watcher "^24.0.0" + jest-worker "^24.0.0" + micromatch "^3.1.10" node-notifier "^5.2.1" - prompts "^0.1.9" + p-each-series "^1.0.0" + pirates "^4.0.0" + prompts "^2.0.1" realpath-native "^1.0.0" rimraf "^2.5.4" - slash "^1.0.0" + slash "^2.0.0" string-length "^2.0.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" which "^1.2.12" - yargs "^11.0.0" + yargs "^12.0.2" -jest-config@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-23.6.0.tgz#f82546a90ade2d8c7026fbf6ac5207fc22f8eb1d" - integrity sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ== +jest-config@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.1.0.tgz#6ea6881cfdd299bc86cc144ee36d937c97c3850c" + integrity sha512-FbbRzRqtFC6eGjG5VwsbW4E5dW3zqJKLWYiZWhB0/4E5fgsMw8GODLbGSrY5t17kKOtCWb/Z7nsIThRoDpuVyg== dependencies: - babel-core "^6.0.0" - babel-jest "^23.6.0" + "@babel/core" "^7.1.0" + babel-jest "^24.1.0" chalk "^2.0.1" glob "^7.1.1" - jest-environment-jsdom "^23.4.0" - jest-environment-node "^23.4.0" - jest-get-type "^22.1.0" - jest-jasmine2 "^23.6.0" - jest-regex-util "^23.3.0" - jest-resolve "^23.6.0" - jest-util "^23.4.0" - jest-validate "^23.6.0" - micromatch "^2.3.11" - pretty-format "^23.6.0" + jest-environment-jsdom "^24.0.0" + jest-environment-node "^24.0.0" + jest-get-type "^24.0.0" + jest-jasmine2 "^24.1.0" + jest-regex-util "^24.0.0" + jest-resolve "^24.1.0" + jest-util "^24.0.0" + jest-validate "^24.0.0" + micromatch "^3.1.10" + pretty-format "^24.0.0" + realpath-native "^1.0.2" jest-diff@^23.6.0: version "23.6.0" @@ -13830,86 +13794,103 @@ jest-diff@^23.6.0: jest-get-type "^22.1.0" pretty-format "^23.6.0" +jest-diff@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.0.0.tgz#a3e5f573dbac482f7d9513ac9cfa21644d3d6b34" + integrity sha512-XY5wMpRaTsuMoU+1/B2zQSKQ9RdE9gsLkGydx3nvApeyPijLA8GtEvIcPwISRCer+VDf9W1mStTYYq6fPt8ryA== + dependencies: + chalk "^2.0.1" + diff-sequences "^24.0.0" + jest-get-type "^24.0.0" + pretty-format "^24.0.0" + jest-docblock@^21.0.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" integrity sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw== -jest-docblock@^23.2.0: - version "23.2.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-23.2.0.tgz#f085e1f18548d99fdd69b20207e6fd55d91383a7" - integrity sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c= +jest-docblock@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.0.0.tgz#54d77a188743e37f62181a91a01eb9222289f94e" + integrity sha512-KfAKZ4SN7CFOZpWg4i7g7MSlY0M+mq7K0aMqENaG2vHuhC9fc3vkpU/iNN9sOus7v3h3Y48uEjqz3+Gdn2iptA== dependencies: detect-newline "^2.1.0" -jest-each@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-23.6.0.tgz#ba0c3a82a8054387016139c733a05242d3d71575" - integrity sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg== +jest-each@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.0.0.tgz#10987a06b21c7ffbfb7706c89d24c52ed864be55" + integrity sha512-gFcbY4Cu55yxExXMkjrnLXov3bWO3dbPAW7HXb31h/DNWdNc/6X8MtxGff8nh3/MjkF9DpVqnj0KsPKuPK0cpA== dependencies: chalk "^2.0.1" - pretty-format "^23.6.0" + jest-get-type "^24.0.0" + jest-util "^24.0.0" + pretty-format "^24.0.0" -jest-environment-jsdom@^23.4.0: - version "23.4.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz#056a7952b3fea513ac62a140a2c368c79d9e6023" - integrity sha1-BWp5UrP+pROsYqFAosNox52eYCM= +jest-environment-jsdom@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.0.0.tgz#5affa0654d6e44cd798003daa1a8701dbd6e4d11" + integrity sha512-1YNp7xtxajTRaxbylDc2pWvFnfDTH5BJJGyVzyGAKNt/lEULohwEV9zFqTgG4bXRcq7xzdd+sGFws+LxThXXOw== dependencies: - jest-mock "^23.2.0" - jest-util "^23.4.0" + jest-mock "^24.0.0" + jest-util "^24.0.0" jsdom "^11.5.1" -jest-environment-node@^23.4.0: - version "23.4.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-23.4.0.tgz#57e80ed0841dea303167cce8cd79521debafde10" - integrity sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA= +jest-environment-node@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.0.0.tgz#330948980656ed8773ce2e04eb597ed91e3c7190" + integrity sha512-62fOFcaEdU0VLaq8JL90TqwI7hLn0cOKOl8vY2n477vRkCJRojiRRtJVRzzCcgFvs6gqU97DNqX5R0BrBP6Rxg== dependencies: - jest-mock "^23.2.0" - jest-util "^23.4.0" + jest-mock "^24.0.0" + jest-util "^24.0.0" jest-get-type@^22.1.0: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" integrity sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w== -jest-haste-map@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-23.6.0.tgz#2e3eb997814ca696d62afdb3f2529f5bbc935e16" - integrity sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg== +jest-get-type@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.0.0.tgz#36e72930b78e33da59a4f63d44d332188278940b" + integrity sha512-z6/Eyf6s9ZDGz7eOvl+fzpuJmN9i0KyTt1no37/dHu8galssxz5ZEgnc1KaV8R31q1khxyhB4ui/X5ZjjPk77w== + +jest-haste-map@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.0.0.tgz#e9ef51b2c9257384b4d6beb83bd48c65b37b5e6e" + integrity sha512-CcViJyUo41IQqttLxXVdI41YErkzBKbE6cS6dRAploCeutePYfUimWd3C9rQEWhX0YBOQzvNsC0O9nYxK2nnxQ== dependencies: fb-watchman "^2.0.0" - graceful-fs "^4.1.11" + graceful-fs "^4.1.15" invariant "^2.2.4" - jest-docblock "^23.2.0" - jest-serializer "^23.0.1" - jest-worker "^23.2.0" - micromatch "^2.3.11" - sane "^2.0.0" + jest-serializer "^24.0.0" + jest-util "^24.0.0" + jest-worker "^24.0.0" + micromatch "^3.1.10" + sane "^3.0.0" -jest-jasmine2@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz#840e937f848a6c8638df24360ab869cc718592e0" - integrity sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ== +jest-jasmine2@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.1.0.tgz#8377324b967037c440f0a549ee0bbd9912055db6" + integrity sha512-H+o76SdSNyCh9fM5K8upK45YTo/DiFx5w2YAzblQebSQmukDcoVBVeXynyr7DDnxh+0NTHYRCLwJVf3tC518wg== dependencies: - babel-traverse "^6.0.0" + "@babel/traverse" "^7.1.0" chalk "^2.0.1" co "^4.6.0" - expect "^23.6.0" - is-generator-fn "^1.0.0" - jest-diff "^23.6.0" - jest-each "^23.6.0" - jest-matcher-utils "^23.6.0" - jest-message-util "^23.4.0" - jest-snapshot "^23.6.0" - jest-util "^23.4.0" - pretty-format "^23.6.0" + expect "^24.1.0" + is-generator-fn "^2.0.0" + jest-each "^24.0.0" + jest-matcher-utils "^24.0.0" + jest-message-util "^24.0.0" + jest-snapshot "^24.1.0" + jest-util "^24.0.0" + pretty-format "^24.0.0" + throat "^4.0.0" -jest-leak-detector@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz#e4230fd42cf381a1a1971237ad56897de7e171de" - integrity sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg== +jest-leak-detector@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.0.0.tgz#78280119fd05ee98317daee62cddb3aa537a31c6" + integrity sha512-ZYHJYFeibxfsDSKowjDP332pStuiFT2xfc5R67Rjm/l+HFJWJgNIOCOlQGeXLCtyUn3A23+VVDdiCcnB6dTTrg== dependencies: - pretty-format "^23.6.0" + pretty-format "^24.0.0" jest-matcher-utils@^23.6.0: version "23.6.0" @@ -13920,6 +13901,16 @@ jest-matcher-utils@^23.6.0: jest-get-type "^22.1.0" pretty-format "^23.6.0" +jest-matcher-utils@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.0.0.tgz#fc9c41cfc49b2c3ec14e576f53d519c37729d579" + integrity sha512-LQTDmO+aWRz1Tf9HJg+HlPHhDh1E1c65kVwRFo5mwCVp5aQDzlkz4+vCvXhOKFjitV2f0kMdHxnODrXVoi+rlA== + dependencies: + chalk "^2.0.1" + jest-diff "^24.0.0" + jest-get-type "^24.0.0" + pretty-format "^24.0.0" + jest-message-util@^23.4.0: version "23.4.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f" @@ -13931,28 +13922,39 @@ jest-message-util@^23.4.0: slash "^1.0.0" stack-utils "^1.0.1" -jest-mock@^23.2.0: - version "23.2.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-23.2.0.tgz#ad1c60f29e8719d47c26e1138098b6d18b261134" - integrity sha1-rRxg8p6HGdR8JuETgJi20YsmETQ= +jest-message-util@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.0.0.tgz#a07a141433b2c992dbaec68d4cbfe470ba289619" + integrity sha512-J9ROJIwz/IeC+eV1XSwnRK4oAwPuhmxEyYx1+K5UI+pIYwFZDSrfZaiWTdq0d2xYFw4Xiu+0KQWsdsQpgJMf3Q== + dependencies: + "@babel/code-frame" "^7.0.0" + chalk "^2.0.1" + micromatch "^3.1.10" + slash "^2.0.0" + stack-utils "^1.0.1" + +jest-mock@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.0.0.tgz#9a4b53e01d66a0e780f7d857462d063e024c617d" + integrity sha512-sQp0Hu5fcf5NZEh1U9eIW2qD0BwJZjb63Yqd98PQJFvf/zzUTBoUAwv/Dc/HFeNHIw1f3hl/48vNn+j3STaI7A== jest-raw-loader@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz#ce9f56d54650f157c4a7d16d224ba5d613bcd626" integrity sha1-zp9W1UZQ8VfEp9FtIkul1hO81iY= -jest-regex-util@^23.3.0: - version "23.3.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-23.3.0.tgz#5f86729547c2785c4002ceaa8f849fe8ca471bc5" - integrity sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U= +jest-regex-util@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.0.0.tgz#4feee8ec4a358f5bee0a654e94eb26163cb9089a" + integrity sha512-Jv/uOTCuC+PY7WpJl2mpoI+WbY2ut73qwwO9ByJJNwOCwr1qWhEW2Lyi2S9ZewUdJqeVpEBisdEVZSI+Zxo58Q== -jest-resolve-dependencies@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz#b4526af24c8540d9a3fab102c15081cf509b723d" - integrity sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA== +jest-resolve-dependencies@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.1.0.tgz#78f738a2ec59ff4d00751d9da56f176e3f589f6c" + integrity sha512-2VwPsjd3kRPu7qe2cpytAgowCObk5AKeizfXuuiwgm1a9sijJDZe8Kh1sFj6FKvSaNEfCPlBVkZEJa2482m/Uw== dependencies: - jest-regex-util "^23.3.0" - jest-snapshot "^23.6.0" + jest-regex-util "^24.0.0" + jest-snapshot "^24.1.0" jest-resolve@^23.6.0: version "23.6.0" @@ -13963,58 +13965,69 @@ jest-resolve@^23.6.0: chalk "^2.0.1" realpath-native "^1.0.0" -jest-runner@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-23.6.0.tgz#3894bd219ffc3f3cb94dc48a4170a2e6f23a5a38" - integrity sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA== +jest-resolve@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.1.0.tgz#42ff0169b0ea47bfdbd0c52a0067ca7d022c7688" + integrity sha512-TPiAIVp3TG6zAxH28u/6eogbwrvZjBMWroSLBDkwkHKrqxB/RIdwkWDye4uqPlZIXWIaHtifY3L0/eO5Z0f2wg== + dependencies: + browser-resolve "^1.11.3" + chalk "^2.0.1" + realpath-native "^1.0.0" + +jest-runner@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.1.0.tgz#3686a2bb89ce62800da23d7fdc3da2c32792943b" + integrity sha512-CDGOkT3AIFl16BLL/OdbtYgYvbAprwJ+ExKuLZmGSCSldwsuU2dEGauqkpvd9nphVdAnJUcP12e/EIlnTX0QXg== dependencies: + chalk "^2.4.2" exit "^0.1.2" - graceful-fs "^4.1.11" - jest-config "^23.6.0" - jest-docblock "^23.2.0" - jest-haste-map "^23.6.0" - jest-jasmine2 "^23.6.0" - jest-leak-detector "^23.6.0" - jest-message-util "^23.4.0" - jest-runtime "^23.6.0" - jest-util "^23.4.0" - jest-worker "^23.2.0" + graceful-fs "^4.1.15" + jest-config "^24.1.0" + jest-docblock "^24.0.0" + jest-haste-map "^24.0.0" + jest-jasmine2 "^24.1.0" + jest-leak-detector "^24.0.0" + jest-message-util "^24.0.0" + jest-runtime "^24.1.0" + jest-util "^24.0.0" + jest-worker "^24.0.0" source-map-support "^0.5.6" throat "^4.0.0" -jest-runtime@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-23.6.0.tgz#059e58c8ab445917cd0e0d84ac2ba68de8f23082" - integrity sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw== +jest-runtime@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.1.0.tgz#7c157a2e776609e8cf552f956a5a19ec9c985214" + integrity sha512-59/BY6OCuTXxGeDhEMU7+N33dpMQyXq7MLK07cNSIY/QYt2QZgJ7Tjx+rykBI0skAoigFl0A5tmT8UdwX92YuQ== dependencies: - babel-core "^6.0.0" - babel-plugin-istanbul "^4.1.6" + "@babel/core" "^7.1.0" + babel-plugin-istanbul "^5.1.0" chalk "^2.0.1" convert-source-map "^1.4.0" exit "^0.1.2" fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.1.11" - jest-config "^23.6.0" - jest-haste-map "^23.6.0" - jest-message-util "^23.4.0" - jest-regex-util "^23.3.0" - jest-resolve "^23.6.0" - jest-snapshot "^23.6.0" - jest-util "^23.4.0" - jest-validate "^23.6.0" - micromatch "^2.3.11" + glob "^7.1.3" + graceful-fs "^4.1.15" + jest-config "^24.1.0" + jest-haste-map "^24.0.0" + jest-message-util "^24.0.0" + jest-regex-util "^24.0.0" + jest-resolve "^24.1.0" + jest-snapshot "^24.1.0" + jest-util "^24.0.0" + jest-validate "^24.0.0" + micromatch "^3.1.10" realpath-native "^1.0.0" - slash "^1.0.0" - strip-bom "3.0.0" - write-file-atomic "^2.1.0" - yargs "^11.0.0" + slash "^2.0.0" + strip-bom "^3.0.0" + write-file-atomic "2.4.1" + yargs "^12.0.2" -jest-serializer@^23.0.1: - version "23.0.1" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165" - integrity sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU= +jest-serializer@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.0.0.tgz#522c44a332cdd194d8c0531eb06a1ee5afb4256b" + integrity sha512-9FKxQyrFgHtx3ozU+1a8v938ILBE7S8Ko3uiAVjT8Yfi2o91j/fj81jacCQZ/Ihjiff/VsUCXVgQ+iF1XdImOw== -jest-snapshot@>=20.0.3, jest-snapshot@^23.6.0: +jest-snapshot@>=20.0.3: version "23.6.0" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.6.0.tgz#f9c2625d1b18acda01ec2d2b826c0ce58a5aa17a" integrity sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg== @@ -14030,6 +14043,22 @@ jest-snapshot@>=20.0.3, jest-snapshot@^23.6.0: pretty-format "^23.6.0" semver "^5.5.0" +jest-snapshot@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.1.0.tgz#85e22f810357aa5994ab61f236617dc2205f2f5b" + integrity sha512-th6TDfFqEmXvuViacU1ikD7xFb7lQsPn2rJl7OEmnfIVpnrx3QNY2t3PE88meeg0u/mQ0nkyvmC05PBqO4USFA== + dependencies: + "@babel/types" "^7.0.0" + chalk "^2.0.1" + jest-diff "^24.0.0" + jest-matcher-utils "^24.0.0" + jest-message-util "^24.0.0" + jest-resolve "^24.1.0" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^24.0.0" + semver "^5.5.0" + jest-specific-snapshot@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jest-specific-snapshot/-/jest-specific-snapshot-1.0.0.tgz#157c79e2534a6fea820fd475f5d17740c8f90833" @@ -14044,53 +14073,56 @@ jest-styled-components@^6.2.2: dependencies: css "^2.2.4" -jest-util@^23.4.0: - version "23.4.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.4.0.tgz#4d063cb927baf0a23831ff61bec2cbbf49793561" - integrity sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE= +jest-util@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.0.0.tgz#fd38fcafd6dedbd0af2944d7a227c0d91b68f7d6" + integrity sha512-QxsALc4wguYS7cfjdQSOr5HTkmjzkHgmZvIDkcmPfl1ib8PNV8QUWLwbKefCudWS0PRKioV+VbQ0oCUPC691fQ== dependencies: - callsites "^2.0.0" + callsites "^3.0.0" chalk "^2.0.1" - graceful-fs "^4.1.11" - is-ci "^1.0.10" - jest-message-util "^23.4.0" + graceful-fs "^4.1.15" + is-ci "^2.0.0" + jest-message-util "^24.0.0" mkdirp "^0.5.1" - slash "^1.0.0" + slash "^2.0.0" source-map "^0.6.0" -jest-validate@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-23.6.0.tgz#36761f99d1ed33fcd425b4e4c5595d62b6597474" - integrity sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A== +jest-validate@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.0.0.tgz#aa8571a46983a6538328fef20406b4a496b6c020" + integrity sha512-vMrKrTOP4BBFIeOWsjpsDgVXATxCspC9S1gqvbJ3Tnn/b9ACsJmteYeVx9830UMV28Cob1RX55x96Qq3Tfad4g== dependencies: + camelcase "^5.0.0" chalk "^2.0.1" - jest-get-type "^22.1.0" + jest-get-type "^24.0.0" leven "^2.1.0" - pretty-format "^23.6.0" + pretty-format "^24.0.0" -jest-watcher@^23.4.0: - version "23.4.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-23.4.0.tgz#d2e28ce74f8dad6c6afc922b92cabef6ed05c91c" - integrity sha1-0uKM50+NrWxq/JIrksq+9u0FyRw= +jest-watcher@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.0.0.tgz#20d44244d10b0b7312410aefd256c1c1eef68890" + integrity sha512-GxkW2QrZ4YxmW1GUWER05McjVDunBlKMFfExu+VsGmXJmpej1saTEKvONdx5RJBlVdpPI5x6E3+EDQSIGgl53g== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.1" + jest-util "^24.0.0" string-length "^2.0.0" -jest-worker@^23.2.0: - version "23.2.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9" - integrity sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk= +jest-worker@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0.tgz#3d3483b077bf04f412f47654a27bba7e947f8b6d" + integrity sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg== dependencies: merge-stream "^1.0.1" + supports-color "^6.1.0" -jest@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-23.6.0.tgz#ad5835e923ebf6e19e7a1d7529a432edfee7813d" - integrity sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw== +jest@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-24.1.0.tgz#b1e1135caefcf2397950ecf7f90e395fde866fd2" + integrity sha512-+q91L65kypqklvlRFfXfdzUKyngQLOcwGhXQaLmVHv+d09LkNXuBuGxlofTFW42XMzu3giIcChchTsCNUjQ78A== dependencies: - import-local "^1.0.0" - jest-cli "^23.6.0" + import-local "^2.0.0" + jest-cli "^24.1.0" jimp@0.2.28: version "0.2.28" @@ -14486,12 +14518,16 @@ jsx-ast-utils@^2.0.1: dependencies: array-includes "^3.0.3" -jszip@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-2.5.0.tgz#7444fd8551ddf3e5da7198fea0c91bc8308cc274" - integrity sha1-dET9hVHd8+XacZj+oMkbyDCMwnQ= +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + integrity sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ== dependencies: - pako "~0.2.5" + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" just-extend@^1.1.27: version "1.1.27" @@ -14673,10 +14709,10 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" -kleur@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.2.tgz#b704f4944d95e255d038f0cb05fb8a602c55a300" - integrity sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ== +kleur@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.2.tgz#83c7ec858a41098b613d5998a7b653962b504f68" + integrity sha512-3h7B2WRT5LNXOtQiAaWonilegHcPSf9nLVXlSTci8lu1dZUuui61+EsPEZqSVxY7rXYmB2DVKMQILxaO5WL61Q== known-css-properties@^0.3.0: version "0.3.0" @@ -14769,14 +14805,6 @@ lead@^1.0.0: dependencies: flush-write-stream "^1.0.2" -leadfoot@1.7.5: - version "1.7.5" - resolved "https://registry.yarnpkg.com/leadfoot/-/leadfoot-1.7.5.tgz#2188019ba95f524f2fec4dd9fbb06f1e6e832d3e" - integrity sha512-NLPJyZ5HYjM2PbMzkpF89EwOboEpyE/ceyLNOmp7TzFZwJQDdxSxdEj3kuJtnfVCUSZXzxvNMUtO300bS+j4nA== - dependencies: - dojo "2.0.0-alpha.7" - jszip "2.5.0" - leaflet-draw@0.4.10: version "0.4.10" resolved "https://registry.yarnpkg.com/leaflet-draw/-/leaflet-draw-0.4.10.tgz#a611a29925a32cde63638e891c3bfc93163e2f43" @@ -14860,6 +14888,13 @@ license-checker@^16.0.0: spdx-satisfies "^0.1.3" treeify "^1.0.1" +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + liftoff@^2.1.0: version "2.5.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec" @@ -15446,27 +15481,12 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= -lodash@4.17.4, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0: - version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" - integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= - lodash@^3.10.0, lodash@^3.10.1, lodash@^3.3.1, lodash@^3.8.0, lodash@~3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= -lodash@^4.0.0, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@~4.17.10: - version "4.17.10" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" - integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== - -lodash@^4.11.1, lodash@^4.17.2, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@^4.8.2, lodash@~4.17.5: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" - integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw== - -lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4: +lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@^4.8.2, lodash@~4.17.10, lodash@~4.17.5: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -15675,7 +15695,7 @@ majo@^0.4.1: globby "^6.1.0" ware "^1.3.0" -make-dir@^1.0.0: +make-dir@^1.0.0, make-dir@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== @@ -15994,7 +16014,7 @@ micromatch@^2.1.5, micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.0.4, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -16729,6 +16749,11 @@ node-int64@^0.4.0: util "^0.10.3" vm-browserify "0.0.4" +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + node-notifier@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" @@ -17427,6 +17452,13 @@ p-defer@^1.0.0: resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= +p-each-series@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" + integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= + dependencies: + p-reduce "^1.0.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -17475,6 +17507,11 @@ p-queue@^2.3.0: resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-2.4.2.tgz#03609826682b743be9a22dba25051bd46724fc34" integrity sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng== +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= + p-retry@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-2.0.0.tgz#b97f1f4d6d81a3c065b2b40107b811e995c1bfba" @@ -17546,11 +17583,16 @@ pad-component@0.0.1: resolved "https://registry.yarnpkg.com/pad-component/-/pad-component-0.0.1.tgz#ad1f22ce1bf0fdc0d6ddd908af17f351a404b8ac" integrity sha1-rR8izhvw/cDW3dkIrxfzUaQEuKw= -pako@^0.2.5, pako@~0.2.5: +pako@^0.2.5: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU= +pako@~1.0.2: + version "1.0.8" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4" + integrity sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA== + pako@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" @@ -17951,6 +17993,13 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +pirates@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + pixelmatch@4.0.2, pixelmatch@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854" @@ -18272,6 +18321,14 @@ pretty-format@^23.6.0: ansi-regex "^3.0.0" ansi-styles "^3.2.0" +pretty-format@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0.tgz#cb6599fd73ac088e37ed682f61291e4678f48591" + integrity sha512-LszZaKG665djUcqg5ZQq+XzezHLKrxsA86ZABTozp+oNhkdqa+tG2dX4qa6ERl5c/sRDrAa3lHmwnvKoP+OG/g== + dependencies: + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -18333,13 +18390,13 @@ promise@^7.0.1, promise@^7.1.1: dependencies: asap "~2.0.3" -prompts@^0.1.9: - version "0.1.14" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-0.1.14.tgz#a8e15c612c5c9ec8f8111847df3337c9cbd443b2" - integrity sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w== +prompts@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.0.3.tgz#c5ccb324010b2e8f74752aadceeb57134c1d2522" + integrity sha512-H8oWEoRZpybm6NV4to9/1limhttEo13xK62pNvn2JzY0MA03p7s0OjtmhXyon3uJmxiJJVSuUwEJFFssI3eBiQ== dependencies: - kleur "^2.0.1" - sisteransi "^0.1.1" + kleur "^3.0.2" + sisteransi "^1.0.0" prop-types@15.5.8: version "15.5.8" @@ -19001,9 +19058,9 @@ react-docgen-typescript@^1.9.0: integrity sha512-s1XswWs4ykNdWKsPyfM4qptV5dT8nnjnVi2IcjoS/vGlRNYrc0TkW0scVOrinHZ+ndKhPqA4iVNrdwhxZBzJcg== react-docgen@^3.0.0-rc.1: - version "3.0.0-rc.2" - resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-3.0.0-rc.2.tgz#5939c64699fd9959da6d97d890f7b648e542dbcc" - integrity sha512-tXbIvq7Hxdc92jW570rztqsz0adtWEM5FX8bShJYozT2Y6L/LeHvBMQcED6mSqJ72niiNMPV8fi3S37OHrGMEw== + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-3.0.0.tgz#79c6e1b1870480c3c2bc1a65bede0577a11c38cd" + integrity sha512-2UseoLWabFNXuk1Foz4VDPSIAkxz+1Hmmq4qijzUmYHDq0ZSloKDLXtGLpQRcAi/M76hRpPtH1rV4BI5jNAOnQ== dependencies: "@babel/parser" "^7.1.3" "@babel/runtime" "^7.0.0" @@ -19624,7 +19681,7 @@ readable-stream@~1.1.0, readable-stream@~1.1.9: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@~2.0.0: +readable-stream@~2.0.0, readable-stream@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= @@ -19646,15 +19703,14 @@ readdir-scoped-modules@^1.0.0: graceful-fs "^4.1.2" once "^1.3.0" -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - integrity sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg= +readdirp@^2.0.0, readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" + graceful-fs "^4.1.11" + micromatch "^3.1.10" readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" readline2@^1.0.1: version "1.0.1" @@ -19672,6 +19728,13 @@ realpath-native@^1.0.0: dependencies: util.promisify "^1.0.0" +realpath-native@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" + integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== + dependencies: + util.promisify "^1.0.0" + recast@^0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/recast/-/recast-0.16.0.tgz#1eb1881cae1f8834b9290caa987349430d5e8526" @@ -19858,6 +19921,13 @@ regenerator-transform@^0.13.3: dependencies: private "^0.1.6" +regenerator-transform@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb" + integrity sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A== + dependencies: + private "^0.1.6" + regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" @@ -20615,14 +20685,15 @@ samsam@1.3.0: resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50" integrity sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg== -sane@^2.0.0: - version "2.5.2" - resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" - integrity sha1-tNwYYcIbQn6SlQej51HiosuKs/o= +sane@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-3.1.0.tgz#995193b7dc1445ef1fe41ddfca2faf9f111854c6" + integrity sha512-G5GClRRxT1cELXfdAq7UKtUsv8q/ZC5k8lQGmjEm4HcAl3HzBy68iglyNCmw4+0tiXPCBZntslHlRhbnsSws+Q== dependencies: anymatch "^2.0.0" capture-exit "^1.2.0" exec-sh "^0.2.0" + execa "^1.0.0" fb-watchman "^2.0.0" micromatch "^3.1.4" minimist "^1.1.1" @@ -20710,16 +20781,6 @@ sass-resources-loader@^2.0.0: glob "^7.1.1" loader-utils "^1.0.4" -sax@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.3.tgz#3773714a0d9157caaa7302971efa5c6dcda552d6" - integrity sha1-N3NxSg2RV8qqcwKXHvpcbc2lUtY= - -sax@0.5.x: - version "0.5.8" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" - integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= - sax@>=0.6.0, sax@^1.2.1, sax@^1.2.4, sax@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -20794,6 +20855,16 @@ select@^1.1.2: resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= +selenium-webdriver@^4.0.0-alpha.1: + version "4.0.0-alpha.1" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.1.tgz#cc93415e21d2dc1dfd85dfc5f6b55f3ac53933b1" + integrity sha512-z88rdjHAv3jmTZ7KSGUkTvo4rGzcDGMq0oXWHNIDK96Gs31JKVdu9+FMtT4KBrVoibg8dUicJDok6GnqqttO5Q== + dependencies: + jszip "^3.1.3" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + selfsigned@^1.9.1: version "1.10.2" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.2.tgz#b4449580d99929b65b10a48389301a6592088758" @@ -20966,7 +21037,7 @@ set-getter@^0.1.0: dependencies: to-object-path "^0.3.0" -set-immediate-shim@^1.0.0, set-immediate-shim@^1.0.1: +set-immediate-shim@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= @@ -21158,10 +21229,10 @@ sinon@^5.0.7: supports-color "^5.1.0" type-detect "^4.0.5" -sisteransi@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce" - integrity sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g== +sisteransi@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c" + integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ== slash@^1.0.0: version "1.0.0" @@ -21879,6 +21950,13 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + strip-bom-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca" @@ -21892,11 +21970,6 @@ strip-bom-string@1.X: resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= -strip-bom@3.0.0, strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - strip-bom@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794" @@ -21912,6 +21985,11 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + strip-dirs@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" @@ -22129,7 +22207,7 @@ supports-color@^5.4.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: +supports-color@^6.0.0, supports-color@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== @@ -22407,6 +22485,16 @@ test-exclude@^4.2.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" +test-exclude@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.1.0.tgz#6ba6b25179d2d38724824661323b73e03c0c1de1" + integrity sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA== + dependencies: + arrify "^1.0.1" + minimatch "^3.0.4" + read-pkg-up "^4.0.0" + require-main-filename "^1.0.1" + text-encoding@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" @@ -22610,6 +22698,13 @@ tmp@0.0.23: resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.23.tgz#de874aa5e974a85f0a32cdfdbd74663cb3bd9c74" integrity sha1-3odKpel0qF8KMs39vXRmPLO9nHQ= +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + integrity sha1-ckGdSovn1s51FI/YsyTlk6cRwu0= + dependencies: + os-tmpdir "~1.0.1" + tmp@0.0.31: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" @@ -22879,17 +22974,6 @@ ts-node@^7.0.1: source-map-support "^0.5.6" yn "^2.0.0" -tsconfig-paths@^3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.8.0.tgz#4e34202d5b41958f269cf56b01ed95b853d59f72" - integrity sha512-zZEYFo4sjORK8W58ENkRn9s+HmQFkkwydDG7My5s/fnfr2YYCaiyXe/HBUcIgU8epEKOXwiahOO+KZYjiXlWyQ== - dependencies: - "@types/json5" "^0.0.29" - deepmerge "^2.0.1" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - tslib@1.9.3, tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.2, tslib@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -23476,10 +23560,10 @@ typescript-fsa@^2.0.0, typescript-fsa@^2.5.0: resolved "https://registry.yarnpkg.com/typescript-fsa/-/typescript-fsa-2.5.0.tgz#1baec01b5e8f5f34c322679d1327016e9e294faf" integrity sha1-G67AG16PXzTDImedEycBbp4pT68= -typescript@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.0.3.tgz#4853b3e275ecdaa27f78fda46dc273a7eb7fc1c8" - integrity sha512-kk80vLW9iGtjMnIv11qyxLqZm20UklzuR2tL0QAnDIygIUIemcZMxlMWudl9OOt76H3ntVzcTiddQ1/pAAJMYg== +typescript@^3.3.3333: + version "3.3.3333" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6" + integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw== ua-parser-js@^0.7.18: version "0.7.18" @@ -23777,7 +23861,7 @@ unzip-response@^2.0.1: resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= -upath@^1.0.0, upath@^1.0.5: +upath@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== @@ -25005,6 +25089,15 @@ wreck@14.x.x, wreck@^14.0.2: boom "7.x.x" hoek "5.x.x" +write-file-atomic@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" + integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + write-file-atomic@^1.1.2: version "1.3.4" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" @@ -25014,7 +25107,7 @@ write-file-atomic@^1.1.2: imurmurhash "^0.1.4" slide "^1.1.5" -write-file-atomic@^2.0.0, write-file-atomic@^2.1.0, write-file-atomic@^2.3.0: +write-file-atomic@^2.0.0, write-file-atomic@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" integrity sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA== @@ -25128,14 +25221,7 @@ xml-parse-from-string@^1.0.0: resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" integrity sha1-qQKekp09vN7RafPG4oI42VpdWig= -xml2js@0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.2.8.tgz#9b81690931631ff09d1957549faf54f4f980b3c2" - integrity sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I= - dependencies: - sax "0.5.x" - -xml2js@^0.4.19, xml2js@^0.4.5: +xml2js@^0.4.17, xml2js@^0.4.19, xml2js@^0.4.5: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== @@ -25143,11 +25229,6 @@ xml2js@^0.4.19, xml2js@^0.4.5: sax ">=0.6.0" xmlbuilder "~9.0.1" -xmlbuilder@0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.2.tgz#1776d65f3fdbad470a08d8604cdeb1c4e540ff83" - integrity sha1-F3bWXz/brUcKCNhgTN6xxOVA/4M= - xmlbuilder@8.2.2: version "8.2.2" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"