diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5a80a11c5cbea..4cc0c8016f1d0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,16 +4,15 @@ Summarize your PR. If it involves visual changes include a screenshot or gif. ### Checklist -Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR. +Delete any items that are not applicable to this PR. -- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md) - [ ] [Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios - [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist) +- [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server) +- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process) -- [ ] This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process) - diff --git a/.github/workflows/pr-project-assigner.yml b/.github/workflows/pr-project-assigner.yml index ccaa5b11aa80c..c85b4b3b8fe79 100644 --- a/.github/workflows/pr-project-assigner.yml +++ b/.github/workflows/pr-project-assigner.yml @@ -8,7 +8,7 @@ jobs: name: Assign a PR to project based on label steps: - name: Assign to project - uses: elastic/github-actions/project-assigner@v1.0.1 + uses: elastic/github-actions/project-assigner@v1.0.2 id: project_assigner with: issue-mappings: | diff --git a/.github/workflows/project-assigner.yml b/.github/workflows/project-assigner.yml index 737da4f7fe371..efcf53c722527 100644 --- a/.github/workflows/project-assigner.yml +++ b/.github/workflows/project-assigner.yml @@ -8,7 +8,7 @@ jobs: name: Assign issue or PR to project based on label steps: - name: Assign to project - uses: elastic/github-actions/project-assigner@v1.0.1 + uses: elastic/github-actions/project-assigner@v1.0.2 id: project_assigner with: issue-mappings: '[{"label": "Team:AppArch", "projectName": "kibana-app-arch", "columnId": 6173895}, {"label": "Feature:Lens", "projectName": "Lens", "columnId": 6219363}, {"label": "Team:Canvas", "projectName": "canvas", "columnId": 6187593}]' diff --git a/.i18nrc.json b/.i18nrc.json index 7d7685b5c1ef1..08cf5a2823203 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -26,12 +26,14 @@ "src/legacy/core_plugins/management", "src/plugins/management" ], + "advancedSettings": "src/plugins/advanced_settings", "kibana_react": "src/legacy/core_plugins/kibana_react", "kibana-react": "src/plugins/kibana_react", "kibana_utils": "src/plugins/kibana_utils", "navigation": "src/plugins/navigation", "newsfeed": "src/plugins/newsfeed", "regionMap": "src/legacy/core_plugins/region_map", + "savedObjects": "src/plugins/saved_objects", "server": "src/legacy/server", "statusPage": "src/legacy/core_plugins/status_page", "telemetry": "src/legacy/core_plugins/telemetry", diff --git a/.node-version b/.node-version index 06c9b9d306348..5b7269c0a98f3 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -10.18.0 +10.19.0 diff --git a/.nvmrc b/.nvmrc index 06c9b9d306348..5b7269c0a98f3 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -10.18.0 +10.19.0 diff --git a/NOTICE.txt b/NOTICE.txt index e0c5d94eff6b3..69be6db72cff2 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -162,8 +162,6 @@ which is available under a "MIT" license. The files based on this license are: - windows_priv_escalation_via_accessibility_features.json - windows_persistence_via_application_shimming.json - windows_execution_via_trusted_developer_utilities.json -- windows_execution_via_net_com_assemblies.json -- windows_execution_via_connection_manager.json MIT License diff --git a/docs/development/core/server/kibana-plugin-server.md b/docs/development/core/server/kibana-plugin-server.md index a3abeff44c25c..482f014b226b9 100644 --- a/docs/development/core/server/kibana-plugin-server.md +++ b/docs/development/core/server/kibana-plugin-server.md @@ -25,6 +25,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectsClient](./kibana-plugin-server.savedobjectsclient.md) | | | [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md) | | | [SavedObjectsRepository](./kibana-plugin-server.savedobjectsrepository.md) | | +| [SavedObjectsSerializer](./kibana-plugin-server.savedobjectsserializer.md) | A serializer that can be used to manually convert [raw](./kibana-plugin-server.savedobjectsrawdoc.md) or [sanitized](./kibana-plugin-server.savedobjectsanitizeddoc.md) documents to the other kind. | | [ScopedClusterClient](./kibana-plugin-server.scopedclusterclient.md) | 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.See [ScopedClusterClient](./kibana-plugin-server.scopedclusterclient.md). | ## Enumerations @@ -106,6 +107,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [RouteValidatorOptions](./kibana-plugin-server.routevalidatoroptions.md) | Additional options for the RouteValidator class to modify its default behaviour. | | [SavedObject](./kibana-plugin-server.savedobject.md) | | | [SavedObjectAttributes](./kibana-plugin-server.savedobjectattributes.md) | The data for a Saved Object is stored as an object in the attributes property. | +| [SavedObjectMigrationMap](./kibana-plugin-server.savedobjectmigrationmap.md) | A map of [migration functions](./kibana-plugin-server.savedobjectmigrationfn.md) to be used for a given type. The map's keys must be valid semver versions.For a given document, only migrations with a higher version number than that of the document will be applied. Migrations are executed in order, starting from the lowest version and ending with the highest one. | | [SavedObjectReference](./kibana-plugin-server.savedobjectreference.md) | A reference to another saved object. | | [SavedObjectsBaseOptions](./kibana-plugin-server.savedobjectsbaseoptions.md) | | | [SavedObjectsBulkCreateObject](./kibana-plugin-server.savedobjectsbulkcreateobject.md) | | @@ -116,6 +118,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectsBulkUpdateResponse](./kibana-plugin-server.savedobjectsbulkupdateresponse.md) | | | [SavedObjectsClientProviderOptions](./kibana-plugin-server.savedobjectsclientprovideroptions.md) | Options to control the creation of the Saved Objects Client. | | [SavedObjectsClientWrapperOptions](./kibana-plugin-server.savedobjectsclientwrapperoptions.md) | Options passed to each SavedObjectsClientWrapperFactory to aid in creating the wrapper instance. | +| [SavedObjectsComplexFieldMapping](./kibana-plugin-server.savedobjectscomplexfieldmapping.md) | See [SavedObjectsFieldMapping](./kibana-plugin-server.savedobjectsfieldmapping.md) for documentation. | +| [SavedObjectsCoreFieldMapping](./kibana-plugin-server.savedobjectscorefieldmapping.md) | See [SavedObjectsFieldMapping](./kibana-plugin-server.savedobjectsfieldmapping.md) for documentation. | | [SavedObjectsCreateOptions](./kibana-plugin-server.savedobjectscreateoptions.md) | | | [SavedObjectsDeleteByNamespaceOptions](./kibana-plugin-server.savedobjectsdeletebynamespaceoptions.md) | | | [SavedObjectsDeleteOptions](./kibana-plugin-server.savedobjectsdeleteoptions.md) | | @@ -132,6 +136,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectsImportUnknownError](./kibana-plugin-server.savedobjectsimportunknownerror.md) | Represents a failure to import due to an unknown reason. | | [SavedObjectsImportUnsupportedTypeError](./kibana-plugin-server.savedobjectsimportunsupportedtypeerror.md) | Represents a failure to import due to having an unsupported saved object type. | | [SavedObjectsIncrementCounterOptions](./kibana-plugin-server.savedobjectsincrementcounteroptions.md) | | +| [SavedObjectsMappingProperties](./kibana-plugin-server.savedobjectsmappingproperties.md) | Describe the fields of a [saved object type](./kibana-plugin-server.savedobjectstypemappingdefinition.md). | | [SavedObjectsMigrationLogger](./kibana-plugin-server.savedobjectsmigrationlogger.md) | | | [SavedObjectsMigrationVersion](./kibana-plugin-server.savedobjectsmigrationversion.md) | Information about the migrations that have been applied to this SavedObject. When Kibana starts up, KibanaMigrator detects outdated documents and migrates them based on this value. For each migration that has been applied, the plugin's name is used as a key and the latest migration version as the value. | | [SavedObjectsRawDoc](./kibana-plugin-server.savedobjectsrawdoc.md) | A raw document as represented directly in the saved object index. | @@ -139,6 +144,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectsResolveImportErrorsOptions](./kibana-plugin-server.savedobjectsresolveimporterrorsoptions.md) | Options to control the "resolve import" operation. | | [SavedObjectsServiceSetup](./kibana-plugin-server.savedobjectsservicesetup.md) | Saved Objects is Kibana's data persistence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceSetup API exposes methods for creating and registering Saved Object client wrappers. | | [SavedObjectsServiceStart](./kibana-plugin-server.savedobjectsservicestart.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceStart API provides a scoped Saved Objects client for interacting with Saved Objects. | +| [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) | | +| [SavedObjectsTypeMappingDefinition](./kibana-plugin-server.savedobjectstypemappingdefinition.md) | Describe a saved object type mapping. | | [SavedObjectsUpdateOptions](./kibana-plugin-server.savedobjectsupdateoptions.md) | | | [SavedObjectsUpdateResponse](./kibana-plugin-server.savedobjectsupdateresponse.md) | | | [SessionCookieValidationResult](./kibana-plugin-server.sessioncookievalidationresult.md) | Return type from a function to validate cookie contents. | @@ -218,10 +225,13 @@ The plugin integrates with the core system via lifecycle events: `setup` | [RouteValidatorFullConfig](./kibana-plugin-server.routevalidatorfullconfig.md) | Route validations config and options merged into one object | | [SavedObjectAttribute](./kibana-plugin-server.savedobjectattribute.md) | Type definition for a Saved Object attribute value | | [SavedObjectAttributeSingle](./kibana-plugin-server.savedobjectattributesingle.md) | Don't use this type, it's simply a helper type for [SavedObjectAttribute](./kibana-plugin-server.savedobjectattribute.md) | +| [SavedObjectMigrationFn](./kibana-plugin-server.savedobjectmigrationfn.md) | A migration function defined for a [saved objects type](./kibana-plugin-server.savedobjectstype.md) used to migrate it's | +| [SavedObjectSanitizedDoc](./kibana-plugin-server.savedobjectsanitizeddoc.md) | | | [SavedObjectsClientContract](./kibana-plugin-server.savedobjectsclientcontract.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state.\#\# SavedObjectsClient errorsSince the SavedObjectsClient has its hands in everything we are a little paranoid about the way we present errors back to to application code. Ideally, all errors will be either:1. Caused by bad implementation (ie. undefined is not a function) and as such unpredictable 2. An error that has been classified and decorated appropriately by the decorators in [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md)Type 1 errors are inevitable, but since all expected/handle-able errors should be Type 2 the isXYZError() helpers exposed at SavedObjectsErrorHelpers should be used to understand and manage error responses from the SavedObjectsClient.Type 2 errors are decorated versions of the source error, so if the elasticsearch client threw an error it will be decorated based on its type. That means that rather than looking for error.body.error.type or doing substring checks on error.body.error.reason, just use the helpers to understand the meaning of the error:\`\`\`js if (SavedObjectsErrorHelpers.isNotFoundError(error)) { // handle 404 }if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling should be automatic, but in case you wanted to know }// always rethrow the error unless you handle it throw error; \`\`\`\#\#\# 404s from missing indexFrom the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistance and that index might be missing.At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages.From my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The object the request/call was targeting could not be found. This is why \#14141 takes special care to ensure that 404 errors are generic and don't distinguish between index missing or document missing.\#\#\# 503s from missing indexUnlike all other methods, create requests are supposed to succeed even when the Kibana index does not exist because it will be automatically created by elasticsearch. When that is not the case it is because Elasticsearch's action.auto_create_index setting prevents it from being created automatically so we throw a special 503 with the intention of informing the user that their Elasticsearch settings need to be updated.See [SavedObjectsClient](./kibana-plugin-server.savedobjectsclient.md) See [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md) | | [SavedObjectsClientFactory](./kibana-plugin-server.savedobjectsclientfactory.md) | Describes the factory used to create instances of the Saved Objects Client. | | [SavedObjectsClientFactoryProvider](./kibana-plugin-server.savedobjectsclientfactoryprovider.md) | Provider to invoke to retrieve a [SavedObjectsClientFactory](./kibana-plugin-server.savedobjectsclientfactory.md). | | [SavedObjectsClientWrapperFactory](./kibana-plugin-server.savedobjectsclientwrapperfactory.md) | Describes the factory used to create instances of Saved Objects Client Wrappers. | +| [SavedObjectsFieldMapping](./kibana-plugin-server.savedobjectsfieldmapping.md) | Describe a [saved object type mapping](./kibana-plugin-server.savedobjectstypemappingdefinition.md) field.Please refer to [elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html) For the mapping documentation | | [ScopeableRequest](./kibana-plugin-server.scopeablerequest.md) | A user credentials container. It accommodates the necessary auth credentials to impersonate the current user.See [KibanaRequest](./kibana-plugin-server.kibanarequest.md). | | [SharedGlobalConfig](./kibana-plugin-server.sharedglobalconfig.md) | | | [StringValidation](./kibana-plugin-server.stringvalidation.md) | Allows regex objects or a regex string | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectmigrationfn.md b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationfn.md new file mode 100644 index 0000000000000..629d748083737 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationfn.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectMigrationFn](./kibana-plugin-server.savedobjectmigrationfn.md) + +## SavedObjectMigrationFn type + +A migration function defined for a [saved objects type](./kibana-plugin-server.savedobjectstype.md) used to migrate it's + +Signature: + +```typescript +export declare type SavedObjectMigrationFn = (doc: SavedObjectUnsanitizedDoc, log: SavedObjectsMigrationLogger) => SavedObjectUnsanitizedDoc; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectmigrationmap.md b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationmap.md new file mode 100644 index 0000000000000..1f49b44f73a72 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationmap.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectMigrationMap](./kibana-plugin-server.savedobjectmigrationmap.md) + +## SavedObjectMigrationMap interface + +A map of [migration functions](./kibana-plugin-server.savedobjectmigrationfn.md) to be used for a given type. The map's keys must be valid semver versions. + +For a given document, only migrations with a higher version number than that of the document will be applied. Migrations are executed in order, starting from the lowest version and ending with the highest one. + +Signature: + +```typescript +export interface SavedObjectMigrationMap +``` + +## Example + + +```typescript +const migrations: SavedObjectMigrationMap = { + '1.0.0': migrateToV1, + '2.1.0': migrateToV21 +} + +``` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsanitizeddoc.md b/docs/development/core/server/kibana-plugin-server.savedobjectsanitizeddoc.md new file mode 100644 index 0000000000000..3c7cd591cd41b --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsanitizeddoc.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectSanitizedDoc](./kibana-plugin-server.savedobjectsanitizeddoc.md) + +## SavedObjectSanitizedDoc type + + +Signature: + +```typescript +export declare type SavedObjectSanitizedDoc = SavedObjectDoc & Referencable; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.dynamic.md b/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.dynamic.md new file mode 100644 index 0000000000000..44e548c611b02 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.dynamic.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsComplexFieldMapping](./kibana-plugin-server.savedobjectscomplexfieldmapping.md) > [dynamic](./kibana-plugin-server.savedobjectscomplexfieldmapping.dynamic.md) + +## SavedObjectsComplexFieldMapping.dynamic property + +Signature: + +```typescript +dynamic?: string; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.md b/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.md new file mode 100644 index 0000000000000..ecb5ec0e88911 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsComplexFieldMapping](./kibana-plugin-server.savedobjectscomplexfieldmapping.md) + +## SavedObjectsComplexFieldMapping interface + +See [SavedObjectsFieldMapping](./kibana-plugin-server.savedobjectsfieldmapping.md) for documentation. + +Signature: + +```typescript +export interface SavedObjectsComplexFieldMapping +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [dynamic](./kibana-plugin-server.savedobjectscomplexfieldmapping.dynamic.md) | string | | +| [properties](./kibana-plugin-server.savedobjectscomplexfieldmapping.properties.md) | SavedObjectsMappingProperties | | +| [type](./kibana-plugin-server.savedobjectscomplexfieldmapping.type.md) | string | | + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.properties.md b/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.properties.md new file mode 100644 index 0000000000000..7ceb0f8ee43c5 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.properties.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsComplexFieldMapping](./kibana-plugin-server.savedobjectscomplexfieldmapping.md) > [properties](./kibana-plugin-server.savedobjectscomplexfieldmapping.properties.md) + +## SavedObjectsComplexFieldMapping.properties property + +Signature: + +```typescript +properties: SavedObjectsMappingProperties; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.type.md b/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.type.md new file mode 100644 index 0000000000000..ef0db5123c927 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscomplexfieldmapping.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsComplexFieldMapping](./kibana-plugin-server.savedobjectscomplexfieldmapping.md) > [type](./kibana-plugin-server.savedobjectscomplexfieldmapping.type.md) + +## SavedObjectsComplexFieldMapping.type property + +Signature: + +```typescript +type?: string; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.enabled.md b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.enabled.md new file mode 100644 index 0000000000000..b7e4203977763 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.enabled.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsCoreFieldMapping](./kibana-plugin-server.savedobjectscorefieldmapping.md) > [enabled](./kibana-plugin-server.savedobjectscorefieldmapping.enabled.md) + +## SavedObjectsCoreFieldMapping.enabled property + +Signature: + +```typescript +enabled?: boolean; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.fields.md b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.fields.md new file mode 100644 index 0000000000000..880ef36cd73fc --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.fields.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsCoreFieldMapping](./kibana-plugin-server.savedobjectscorefieldmapping.md) > [fields](./kibana-plugin-server.savedobjectscorefieldmapping.fields.md) + +## SavedObjectsCoreFieldMapping.fields property + +Signature: + +```typescript +fields?: { + [subfield: string]: { + type: string; + }; + }; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.index.md b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.index.md new file mode 100644 index 0000000000000..31ff5a1d51948 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.index.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsCoreFieldMapping](./kibana-plugin-server.savedobjectscorefieldmapping.md) > [index](./kibana-plugin-server.savedobjectscorefieldmapping.index.md) + +## SavedObjectsCoreFieldMapping.index property + +Signature: + +```typescript +index?: boolean; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.md b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.md new file mode 100644 index 0000000000000..4287921997098 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsCoreFieldMapping](./kibana-plugin-server.savedobjectscorefieldmapping.md) + +## SavedObjectsCoreFieldMapping interface + +See [SavedObjectsFieldMapping](./kibana-plugin-server.savedobjectsfieldmapping.md) for documentation. + +Signature: + +```typescript +export interface SavedObjectsCoreFieldMapping +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [enabled](./kibana-plugin-server.savedobjectscorefieldmapping.enabled.md) | boolean | | +| [fields](./kibana-plugin-server.savedobjectscorefieldmapping.fields.md) | {
[subfield: string]: {
type: string;
};
} | | +| [index](./kibana-plugin-server.savedobjectscorefieldmapping.index.md) | boolean | | +| [type](./kibana-plugin-server.savedobjectscorefieldmapping.type.md) | string | | + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.type.md b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.type.md new file mode 100644 index 0000000000000..8071217af861f --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectscorefieldmapping.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsCoreFieldMapping](./kibana-plugin-server.savedobjectscorefieldmapping.md) > [type](./kibana-plugin-server.savedobjectscorefieldmapping.type.md) + +## SavedObjectsCoreFieldMapping.type property + +Signature: + +```typescript +type: string; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsfieldmapping.md b/docs/development/core/server/kibana-plugin-server.savedobjectsfieldmapping.md new file mode 100644 index 0000000000000..f31e18e8df670 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsfieldmapping.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsFieldMapping](./kibana-plugin-server.savedobjectsfieldmapping.md) + +## SavedObjectsFieldMapping type + +Describe a [saved object type mapping](./kibana-plugin-server.savedobjectstypemappingdefinition.md) field. + +Please refer to [elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html) For the mapping documentation + +Signature: + +```typescript +export declare type SavedObjectsFieldMapping = SavedObjectsCoreFieldMapping | SavedObjectsComplexFieldMapping; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsmappingproperties.md b/docs/development/core/server/kibana-plugin-server.savedobjectsmappingproperties.md new file mode 100644 index 0000000000000..23c5a83afc1f8 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsmappingproperties.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsMappingProperties](./kibana-plugin-server.savedobjectsmappingproperties.md) + +## SavedObjectsMappingProperties interface + +Describe the fields of a [saved object type](./kibana-plugin-server.savedobjectstypemappingdefinition.md). + +Signature: + +```typescript +export interface SavedObjectsMappingProperties +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.md b/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.md index a98d88700cd55..1b8db4a6c9f8d 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.md @@ -17,5 +17,6 @@ export interface SavedObjectsMigrationLogger | --- | --- | --- | | [debug](./kibana-plugin-server.savedobjectsmigrationlogger.debug.md) | (msg: string) => void | | | [info](./kibana-plugin-server.savedobjectsmigrationlogger.info.md) | (msg: string) => void | | +| [warn](./kibana-plugin-server.savedobjectsmigrationlogger.warn.md) | (msg: string) => void | | | [warning](./kibana-plugin-server.savedobjectsmigrationlogger.warning.md) | (msg: string) => void | | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.warn.md b/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.warn.md new file mode 100644 index 0000000000000..7ebb1dd5ee4d2 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.warn.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsMigrationLogger](./kibana-plugin-server.savedobjectsmigrationlogger.md) > [warn](./kibana-plugin-server.savedobjectsmigrationlogger.warn.md) + +## SavedObjectsMigrationLogger.warn property + +Signature: + +```typescript +warn: (msg: string) => void; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.warning.md b/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.warning.md index a87955d603b70..689a799515094 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.warning.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsmigrationlogger.warning.md @@ -4,6 +4,11 @@ ## SavedObjectsMigrationLogger.warning property +> Warning: This API is now obsolete. +> +> Use `warn` instead. +> + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrawdoc._source.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrawdoc._source.md index dcf207f8120ea..332df982b23eb 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrawdoc._source.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrawdoc._source.md @@ -7,5 +7,5 @@ Signature: ```typescript -_source: any; +_source: SavedObjectsRawDocSource; ``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrawdoc.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrawdoc.md index b0130df01817f..3e3ad7da5aecd 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrawdoc.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrawdoc.md @@ -9,7 +9,7 @@ A raw document as represented directly in the saved object index. Signature: ```typescript -export interface RawDoc +export interface SavedObjectsRawDoc ``` ## Properties @@ -19,6 +19,6 @@ export interface RawDoc | [\_id](./kibana-plugin-server.savedobjectsrawdoc._id.md) | string | | | [\_primary\_term](./kibana-plugin-server.savedobjectsrawdoc._primary_term.md) | number | | | [\_seq\_no](./kibana-plugin-server.savedobjectsrawdoc._seq_no.md) | number | | -| [\_source](./kibana-plugin-server.savedobjectsrawdoc._source.md) | any | | +| [\_source](./kibana-plugin-server.savedobjectsrawdoc._source.md) | SavedObjectsRawDocSource | | | [\_type](./kibana-plugin-server.savedobjectsrawdoc._type.md) | string | | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.generaterawid.md b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.generaterawid.md new file mode 100644 index 0000000000000..50fb4433b33c8 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.generaterawid.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsSerializer](./kibana-plugin-server.savedobjectsserializer.md) > [generateRawId](./kibana-plugin-server.savedobjectsserializer.generaterawid.md) + +## SavedObjectsSerializer.generateRawId() method + +Given a saved object type and id, generates the compound id that is stored in the raw document. + +Signature: + +```typescript +generateRawId(namespace: string | undefined, type: string, id?: string): string; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| namespace | string | undefined | | +| type | string | | +| id | string | | + +Returns: + +`string` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.israwsavedobject.md b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.israwsavedobject.md new file mode 100644 index 0000000000000..32d00ee1a9f7f --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.israwsavedobject.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsSerializer](./kibana-plugin-server.savedobjectsserializer.md) > [isRawSavedObject](./kibana-plugin-server.savedobjectsserializer.israwsavedobject.md) + +## SavedObjectsSerializer.isRawSavedObject() method + +Determines whether or not the raw document can be converted to a saved object. + +Signature: + +```typescript +isRawSavedObject(rawDoc: SavedObjectsRawDoc): boolean; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| rawDoc | SavedObjectsRawDoc | | + +Returns: + +`boolean` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.md b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.md new file mode 100644 index 0000000000000..5fa84af147b40 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.md @@ -0,0 +1,29 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsSerializer](./kibana-plugin-server.savedobjectsserializer.md) + +## SavedObjectsSerializer class + +A serializer that can be used to manually convert [raw](./kibana-plugin-server.savedobjectsrawdoc.md) or [sanitized](./kibana-plugin-server.savedobjectsanitizeddoc.md) documents to the other kind. + +Signature: + +```typescript +export declare class SavedObjectsSerializer +``` + +## Remarks + +Serializer instances should only be created and accessed by calling [SavedObjectsServiceStart.createSerializer](./kibana-plugin-server.savedobjectsservicestart.createserializer.md) + +The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `SavedObjectsSerializer` class. + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [generateRawId(namespace, type, id)](./kibana-plugin-server.savedobjectsserializer.generaterawid.md) | | Given a saved object type and id, generates the compound id that is stored in the raw document. | +| [isRawSavedObject(rawDoc)](./kibana-plugin-server.savedobjectsserializer.israwsavedobject.md) | | Determines whether or not the raw document can be converted to a saved object. | +| [rawToSavedObject(doc)](./kibana-plugin-server.savedobjectsserializer.rawtosavedobject.md) | | Converts a document from the format that is stored in elasticsearch to the saved object client format. | +| [savedObjectToRaw(savedObj)](./kibana-plugin-server.savedobjectsserializer.savedobjecttoraw.md) | | Converts a document from the saved object client format to the format that is stored in elasticsearch. | + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.rawtosavedobject.md b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.rawtosavedobject.md new file mode 100644 index 0000000000000..6a8a006241297 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.rawtosavedobject.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsSerializer](./kibana-plugin-server.savedobjectsserializer.md) > [rawToSavedObject](./kibana-plugin-server.savedobjectsserializer.rawtosavedobject.md) + +## SavedObjectsSerializer.rawToSavedObject() method + +Converts a document from the format that is stored in elasticsearch to the saved object client format. + +Signature: + +```typescript +rawToSavedObject(doc: SavedObjectsRawDoc): SavedObjectSanitizedDoc; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| doc | SavedObjectsRawDoc | | + +Returns: + +`SavedObjectSanitizedDoc` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.savedobjecttoraw.md b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.savedobjecttoraw.md new file mode 100644 index 0000000000000..b0d2043665b54 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsserializer.savedobjecttoraw.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsSerializer](./kibana-plugin-server.savedobjectsserializer.md) > [savedObjectToRaw](./kibana-plugin-server.savedobjectsserializer.savedobjecttoraw.md) + +## SavedObjectsSerializer.savedObjectToRaw() method + +Converts a document from the saved object client format to the format that is stored in elasticsearch. + +Signature: + +```typescript +savedObjectToRaw(savedObj: SavedObjectSanitizedDoc): SavedObjectsRawDoc; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| savedObj | SavedObjectSanitizedDoc | | + +Returns: + +`SavedObjectsRawDoc` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.md b/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.md index 64fb1f4a5f638..9981bfee0cb7d 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.md @@ -20,9 +20,19 @@ When plugins access the Saved Objects client, a new client is created using the ## Example + +```ts import { SavedObjectsClient, CoreSetup } from 'src/core/server'; -export class Plugin() { setup: (core: CoreSetup) => { core.savedObjects.setClientFactory(({ request: KibanaRequest }) => { return new SavedObjectsClient(core.savedObjects.scopedRepository(request)); }) } } +export class Plugin() { + setup: (core: CoreSetup) => { + core.savedObjects.setClientFactory(({ request: KibanaRequest }) => { + return new SavedObjectsClient(core.savedObjects.scopedRepository(request)); + }) + } +} + +``` ## Properties diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.createserializer.md b/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.createserializer.md new file mode 100644 index 0000000000000..b0e7ae1db89c1 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.createserializer.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsServiceStart](./kibana-plugin-server.savedobjectsservicestart.md) > [createSerializer](./kibana-plugin-server.savedobjectsservicestart.createserializer.md) + +## SavedObjectsServiceStart.createSerializer property + +Creates a [serializer](./kibana-plugin-server.savedobjectsserializer.md) that is aware of all registered types. + +Signature: + +```typescript +createSerializer: () => SavedObjectsSerializer; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.md b/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.md index cf2b4f57a7461..ad34d76bb33f4 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.md @@ -18,5 +18,6 @@ export interface SavedObjectsServiceStart | --- | --- | --- | | [createInternalRepository](./kibana-plugin-server.savedobjectsservicestart.createinternalrepository.md) | (extraTypes?: string[]) => ISavedObjectsRepository | Creates a [Saved Objects repository](./kibana-plugin-server.isavedobjectsrepository.md) that uses the internal Kibana user for authenticating with Elasticsearch. | | [createScopedRepository](./kibana-plugin-server.savedobjectsservicestart.createscopedrepository.md) | (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository | Creates a [Saved Objects repository](./kibana-plugin-server.isavedobjectsrepository.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. | +| [createSerializer](./kibana-plugin-server.savedobjectsservicestart.createserializer.md) | () => SavedObjectsSerializer | Creates a [serializer](./kibana-plugin-server.savedobjectsserializer.md) that is aware of all registered types. | | [getScopedClient](./kibana-plugin-server.savedobjectsservicestart.getscopedclient.md) | (req: KibanaRequest, options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract | Creates a [Saved Objects client](./kibana-plugin-server.savedobjectsclientcontract.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. If other plugins have registered Saved Objects client wrappers, these will be applied to extend the functionality of the client.A client that is already scoped to the incoming request is also exposed from the route handler context see [RequestHandlerContext](./kibana-plugin-server.requesthandlercontext.md). | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstype.converttoaliasscript.md b/docs/development/core/server/kibana-plugin-server.savedobjectstype.converttoaliasscript.md new file mode 100644 index 0000000000000..f2519b2600e2f --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstype.converttoaliasscript.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) > [convertToAliasScript](./kibana-plugin-server.savedobjectstype.converttoaliasscript.md) + +## SavedObjectsType.convertToAliasScript property + +If defined, will be used to convert the type to an alias. + +Signature: + +```typescript +convertToAliasScript?: string; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstype.hidden.md b/docs/development/core/server/kibana-plugin-server.savedobjectstype.hidden.md new file mode 100644 index 0000000000000..9e611bc8faf27 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstype.hidden.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) > [hidden](./kibana-plugin-server.savedobjectstype.hidden.md) + +## SavedObjectsType.hidden property + +Is the type hidden by default. If true, repositories will not have access to this type unless explicitly declared as an `extraType` when creating the repository. + +See [createInternalRepository](./kibana-plugin-server.savedobjectsservicestart.createinternalrepository.md). + +Signature: + +```typescript +hidden: boolean; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstype.indexpattern.md b/docs/development/core/server/kibana-plugin-server.savedobjectstype.indexpattern.md new file mode 100644 index 0000000000000..18cb6fe936060 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstype.indexpattern.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) > [indexPattern](./kibana-plugin-server.savedobjectstype.indexpattern.md) + +## SavedObjectsType.indexPattern property + +If defined, the type instances will be stored in the given index instead of the default one. + +Signature: + +```typescript +indexPattern?: string; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstype.mappings.md b/docs/development/core/server/kibana-plugin-server.savedobjectstype.mappings.md new file mode 100644 index 0000000000000..3166a2604d728 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstype.mappings.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) > [mappings](./kibana-plugin-server.savedobjectstype.mappings.md) + +## SavedObjectsType.mappings property + +The [mapping definition](./kibana-plugin-server.savedobjectstypemappingdefinition.md) for the type. + +Signature: + +```typescript +mappings: SavedObjectsTypeMappingDefinition; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstype.md b/docs/development/core/server/kibana-plugin-server.savedobjectstype.md new file mode 100644 index 0000000000000..1e989652e52bf --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstype.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) + +## SavedObjectsType interface + +Signature: + +```typescript +export interface SavedObjectsType +``` + +## Remarks + +This is only internal for now, and will only be public when we expose the registerType API + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [convertToAliasScript](./kibana-plugin-server.savedobjectstype.converttoaliasscript.md) | string | If defined, will be used to convert the type to an alias. | +| [hidden](./kibana-plugin-server.savedobjectstype.hidden.md) | boolean | Is the type hidden by default. If true, repositories will not have access to this type unless explicitly declared as an extraType when creating the repository.See [createInternalRepository](./kibana-plugin-server.savedobjectsservicestart.createinternalrepository.md). | +| [indexPattern](./kibana-plugin-server.savedobjectstype.indexpattern.md) | string | If defined, the type instances will be stored in the given index instead of the default one. | +| [mappings](./kibana-plugin-server.savedobjectstype.mappings.md) | SavedObjectsTypeMappingDefinition | The [mapping definition](./kibana-plugin-server.savedobjectstypemappingdefinition.md) for the type. | +| [migrations](./kibana-plugin-server.savedobjectstype.migrations.md) | SavedObjectMigrationMap | An optional map of [migrations](./kibana-plugin-server.savedobjectmigrationfn.md) to be used to migrate the type. | +| [name](./kibana-plugin-server.savedobjectstype.name.md) | string | The name of the type, which is also used as the internal id. | +| [namespaceAgnostic](./kibana-plugin-server.savedobjectstype.namespaceagnostic.md) | boolean | Is the type global (true), or namespaced (false). | + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstype.migrations.md b/docs/development/core/server/kibana-plugin-server.savedobjectstype.migrations.md new file mode 100644 index 0000000000000..a7f933ef6e3f7 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstype.migrations.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) > [migrations](./kibana-plugin-server.savedobjectstype.migrations.md) + +## SavedObjectsType.migrations property + +An optional map of [migrations](./kibana-plugin-server.savedobjectmigrationfn.md) to be used to migrate the type. + +Signature: + +```typescript +migrations?: SavedObjectMigrationMap; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstype.name.md b/docs/development/core/server/kibana-plugin-server.savedobjectstype.name.md new file mode 100644 index 0000000000000..444152d239cdf --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstype.name.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) > [name](./kibana-plugin-server.savedobjectstype.name.md) + +## SavedObjectsType.name property + +The name of the type, which is also used as the internal id. + +Signature: + +```typescript +name: string; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstype.namespaceagnostic.md b/docs/development/core/server/kibana-plugin-server.savedobjectstype.namespaceagnostic.md new file mode 100644 index 0000000000000..5c68942276ec7 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstype.namespaceagnostic.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) > [namespaceAgnostic](./kibana-plugin-server.savedobjectstype.namespaceagnostic.md) + +## SavedObjectsType.namespaceAgnostic property + +Is the type global (true), or namespaced (false). + +Signature: + +```typescript +namespaceAgnostic: boolean; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstypemappingdefinition.md b/docs/development/core/server/kibana-plugin-server.savedobjectstypemappingdefinition.md new file mode 100644 index 0000000000000..99983d3a9f02b --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstypemappingdefinition.md @@ -0,0 +1,45 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsTypeMappingDefinition](./kibana-plugin-server.savedobjectstypemappingdefinition.md) + +## SavedObjectsTypeMappingDefinition interface + +Describe a saved object type mapping. + +Signature: + +```typescript +export interface SavedObjectsTypeMappingDefinition +``` + +## Example + + +```ts +const typeDefinition: SavedObjectsTypeMappingDefinition = { + properties: { + enabled: { + type: "boolean" + }, + sendUsageFrom: { + ignore_above: 256, + type: "keyword" + }, + lastReported: { + type: "date" + }, + lastVersionChecked: { + ignore_above: 256, + type: "keyword" + }, + } +} + +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [properties](./kibana-plugin-server.savedobjectstypemappingdefinition.properties.md) | SavedObjectsMappingProperties | | + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectstypemappingdefinition.properties.md b/docs/development/core/server/kibana-plugin-server.savedobjectstypemappingdefinition.properties.md new file mode 100644 index 0000000000000..555870c3fdd7d --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectstypemappingdefinition.properties.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsTypeMappingDefinition](./kibana-plugin-server.savedobjectstypemappingdefinition.md) > [properties](./kibana-plugin-server.savedobjectstypemappingdefinition.properties.md) + +## SavedObjectsTypeMappingDefinition.properties property + +Signature: + +```typescript +properties: SavedObjectsMappingProperties; +``` diff --git a/docs/images/management-index-patterns.png b/docs/images/management-index-patterns.png new file mode 100644 index 0000000000000..232d32893b96d Binary files /dev/null and b/docs/images/management-index-patterns.png differ diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 695a4d4f45b02..d4d766c1f5442 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -1,7 +1,7 @@ [[advanced-options]] -== Setting advanced options +== Advanced Settings -The *Advanced Settings* page enables you to directly edit settings that control the behavior of the Kibana application. +The *Advanced Settings* UI enables you to edit settings that control the behavior of Kibana. For example, you can change the format used to display dates, specify the default index pattern, and set the precision for displayed decimal values. diff --git a/docs/management/index-lifecycle-policies/intro-to-lifecycle-policies.asciidoc b/docs/management/index-lifecycle-policies/intro-to-lifecycle-policies.asciidoc index 79bd0b8be3ce9..ba1d79710de05 100644 --- a/docs/management/index-lifecycle-policies/intro-to-lifecycle-policies.asciidoc +++ b/docs/management/index-lifecycle-policies/intro-to-lifecycle-policies.asciidoc @@ -1,30 +1,30 @@ [role="xpack"] [[index-lifecycle-policies]] -== Index lifecycle policies +== Index Lifecycle Policies -If you're working with time series data, you don't want to continually dump -everything into a single index. Instead, you might periodically roll over the -data to a new index to keep it from growing so big it's slow and expensive. -As the index ages and you query it less frequently, you’ll likely move it to +If you're working with time series data, you don't want to continually dump +everything into a single index. Instead, you might periodically roll over the +data to a new index to keep it from growing so big it's slow and expensive. +As the index ages and you query it less frequently, you’ll likely move it to less expensive hardware and reduce the number of shards and replicas. -To automatically move an index through its lifecycle, you can create a policy -to define actions to perform on the index as it ages. Index lifecycle policies -are especially useful when working with {beats-ref}/beats-reference.html[Beats] -data shippers, which continually -send operational data, such as metrics and logs, to Elasticsearch. You can -automate a rollover to a new index when the existing index reaches a specified -size or age. This ensures that all indices have a similar size instead of having -daily indices where size can vary based on the number of Beats and the number +To automatically move an index through its lifecycle, you can create a policy +to define actions to perform on the index as it ages. Index lifecycle policies +are especially useful when working with {beats-ref}/beats-reference.html[Beats] +data shippers, which continually +send operational data, such as metrics and logs, to Elasticsearch. You can +automate a rollover to a new index when the existing index reaches a specified +size or age. This ensures that all indices have a similar size instead of having +daily indices where size can vary based on the number of Beats and the number of events sent. -{kib}’s *Index Lifecycle Policies* walks you through the process for creating -and configuring a policy. Before using this feature, you should be familiar +{kib}’s *Index Lifecycle Policies* walks you through the process for creating +and configuring a policy. Before using this feature, you should be familiar with index lifecycle management: -* For an introduction, see -{ref}/getting-started-index-lifecycle-management.html[Getting started with index -lifecycle management]. -* To dig into the concepts and technical details, see +* For an introduction, refer to +{ref}/getting-started-index-lifecycle-management.html[Getting started with index +lifecycle management]. +* To dig into the concepts and technical details, see {ref}/index-lifecycle-management.html[Managing the index lifecycle]. * To check out the APIs, see {ref}/index-lifecycle-management-api.html[Index lifecycle management API]. diff --git a/docs/management/index-patterns.asciidoc b/docs/management/index-patterns.asciidoc index 8e687f641c92b..d8073e4590c3c 100644 --- a/docs/management/index-patterns.asciidoc +++ b/docs/management/index-patterns.asciidoc @@ -89,39 +89,11 @@ pattern: `*:logstash-*`. Once an index pattern is configured using the {ccs} syntax, all searches and aggregations using that index pattern in {kib} take advantage of {ccs}. + [float] +[[reload-fields]] === Manage your index pattern -Once you create an index pattern, manually or with a sample data set, -you can look at its fields and associated data types. -You can also perform housekeeping tasks, such as making the -index pattern the default or deleting it when you longer need it. -To drill down into the details of an index pattern, click its name in -the *Index patterns* overview. - -[role="screenshot"] -image:management/index-patterns/images/new-index-pattern.png["Index files and data types"] - -From the detailed view, you can perform the following actions: - -* *Manage the index fields.* You can add formatters to format values and create -scripted fields. -See <> for more information. - -* [[set-default-pattern]]*Set the default index pattern.* {kib} uses a badge to make users -aware of which index pattern is the default. The first pattern -you create is automatically designated as the default pattern. The default -index pattern is loaded when you open *Discover*. - -* [[reload-fields]]*Refresh the index fields list.* You can refresh the index fields list to -pick up any newly-added fields. Doing so also resets Kibana’s popularity counters -for the fields. The popularity counters are used in *Discover* to sort fields in lists. - -* [[delete-pattern]]*Delete the index pattern.* This action removes the pattern from the list of -Saved Objects in {kib}. You will not be able to recover field formatters, -scripted fields, source filters, and field popularity data associated with the index pattern. -Deleting an index pattern does -not remove any indices or data documents from {es}. -+ -WARNING: Deleting an index pattern breaks all visualizations, saved searches, and -other saved objects that reference the pattern. +To drill down into the fields and associated data types in an index pattern, +click its name in the *Index patterns* overview page. +For more information, refer to <>. diff --git a/docs/management/index-patterns/images/edit_icon.png b/docs/management/index-patterns/images/edit_icon.png new file mode 100644 index 0000000000000..d5af1751809cc Binary files /dev/null and b/docs/management/index-patterns/images/edit_icon.png differ diff --git a/docs/management/managing-beats.asciidoc b/docs/management/managing-beats.asciidoc index 13e8f52f29b87..5a23b60307131 100644 --- a/docs/management/managing-beats.asciidoc +++ b/docs/management/managing-beats.asciidoc @@ -1,6 +1,6 @@ [[managing-beats]] [role="xpack"] -== Managing {beats} +== {beats} Central Management include::{asciidoc-dir}/../../shared/discontinued.asciidoc[tag=cm-discontinued] @@ -34,14 +34,14 @@ Central Management UI. You need to enroll {beats} to register them in central management and establish trust. Enrolled {beats} will have the credentials needed to retrieve -configurations from {kib}. +configurations from {kib}. [float] === Create configuration tags A _configuration tag_ is a group of configuration blocks that you can apply to one or more {beats}. For example, you can create a tag called `development` to -group configurations for {beats} running in your development environment. +group configurations for {beats} running in your development environment. The first time you walk through the enrollment process, you'll create a configuration tag that's applied to the {beats} instance you're enrolling. @@ -62,7 +62,7 @@ Central management supports configuration settings for: * {filebeat} modules * {metricbeat} modules * {filebeat} inputs -* {filebeat} and {metricbeat} outputs +* {filebeat} and {metricbeat} outputs NOTE: Central management supports the following outputs only: {es}, {ls}, Kafka, and Redis. Other output types are not supported for {beats} that are enrolled in @@ -72,7 +72,7 @@ Use the Central Management UI to define and manage settings for supported configuration blocks. You cannot define those settings in local {beats} configuration files. For configuration blocks that are not supported by central management, configure the settings in the local configuration file after -enrolling the Beat in central management. +enrolling the Beat in central management. [float] === Manage enrolled {beats} diff --git a/docs/management/managing-fields.asciidoc b/docs/management/managing-fields.asciidoc index 308e61abf70e5..f66976b3715d1 100644 --- a/docs/management/managing-fields.asciidoc +++ b/docs/management/managing-fields.asciidoc @@ -1,12 +1,56 @@ [[managing-fields]] -== Managing Fields +== Index Patterns and Fields -The fields for the index pattern are listed in a table. Click a column header to sort the table by that column. Click -the *Controls* button in the rightmost column for a given field to edit the field's properties. You can manually set -the field's format from the *Format* drop-down. Format options vary based on the field's type. +The *Index patterns* UI helps you create and manage +the index patterns that retrieve your data from Elasticsearch. -You can also set the field's popularity value in the *Popularity* text entry box to any desired value. Click the -*Update Field* button to confirm your changes or *Cancel* to return to the list of fields. +[role="screenshot"] +image::images/management-index-patterns.png[] + +[float] +=== Create an index pattern + +An index pattern is the glue that connects Kibana to your Elasticsearch data. Create an +index pattern whenever you load your own data into Kibana. To get started, +click *Create index pattern*, and then follow the guided steps. Refer to +<> for the types of index patterns +that you can create. + +[float] +=== Manage your index pattern + +To view the fields and associated data types in an index pattern, click its name in +the *Index patterns* overview. + +[role="screenshot"] +image::management/index-patterns/images/new-index-pattern.png["Index files and data types"] + +Use the icons in the upper right to perform the following actions: + +* [[set-default-pattern]]*Set the default index pattern.* {kib} uses a badge to make users +aware of which index pattern is the default. The first pattern +you create is automatically designated as the default pattern. The default +index pattern is loaded when you open *Discover*. + +* *Refresh the index fields list.* You can refresh the index fields list to +pick up any newly-added fields. Doing so also resets Kibana’s popularity counters +for the fields. The popularity counters are used in *Discover* to sort fields in lists. + +* [[delete-pattern]]*Delete the index pattern.* This action removes the pattern from the list of +Saved Objects in {kib}. You will not be able to recover field formatters, +scripted fields, source filters, and field popularity data associated with the index pattern. +Deleting an index pattern does +not remove any indices or data documents from {es}. ++ +WARNING: Deleting an index pattern breaks all visualizations, saved searches, and +other saved objects that reference the pattern. + +[float] +=== Edit a field + +To edit a field's properties, click the edit icon +image:management/index-patterns/images/edit_icon.png[] in the detail view. +You can set the field's format and popularity value. Kibana has field formatters for the following field types: diff --git a/docs/management/managing-indices.asciidoc b/docs/management/managing-indices.asciidoc index 7a3480c860b16..933a2ffbf6ee2 100644 --- a/docs/management/managing-indices.asciidoc +++ b/docs/management/managing-indices.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[managing-indices]] -== Index management +== Index Management *Index Management* enables you to view index settings, mappings, and statistics and perform index-level operations. @@ -127,7 +127,7 @@ under the *Mapped fields* tab as follows: image::images/management-index-templates-mappings.png[Mapped fields page] You can create additional mapping configurations in the *Dynamic templates* and -*Advanced options* tabs. No additional mappings are required for this example. +*Advanced options* tabs. No additional mappings are required for this example. In the fourth step, define an alias named `logstash`. diff --git a/docs/management/managing-licenses.asciidoc b/docs/management/managing-licenses.asciidoc index ecb550d3ab267..72accdb5fe2aa 100644 --- a/docs/management/managing-licenses.asciidoc +++ b/docs/management/managing-licenses.asciidoc @@ -1,32 +1,32 @@ [[managing-licenses]] -== License management +== License Management When you install the default distribution of {kib}, you receive a basic license with no expiration date. For the full list of free features that are included in -the basic license, see https://www.elastic.co/subscriptions[the subscription page]. +the basic license, refer to https://www.elastic.co/subscriptions[the subscription page]. If you want to try out the full set of platinum features, you can activate a -30-day trial license. Go to *Management > License Management* to view the +30-day trial license. Go to *Management > License Management* to view the status of your license, start a trial, or install a new license. NOTE: You can start a trial only if your cluster has not already activated a trial license for the current major product version. For example, if you have -already activated a trial for v6.0, you cannot start a new trial until -v7.0. You can, however, contact `info@elastic.co` to request an extended trial +already activated a trial for 6.0, you cannot start a new trial until +7.0. You can, however, contact `info@elastic.co` to request an extended trial license. -When you activate a new license level, new features appear in the left sidebar +When you activate a new license level, new features appear in the left sidebar of the *Management* page. [role="screenshot"] image::images/management-license.png[] At the end of the trial period, the platinum features operate in a -<>. You can revert to a basic license, -extend the trial, or purchase a subscription. +<>. You can revert to a basic license, +extend the trial, or purchase a subscription. -TIP: If {security-features} are enabled, unless you have a trial license, -you must configure Transport Layer Security (TLS) in {es}. +TIP: If {security-features} are enabled, unless you have a trial license, +you must configure Transport Layer Security (TLS) in {es}. See {ref}/encrypting-communications.html[Encrypting communications]. {kib} and the {ref}/start-basic.html[start basic API] provide a list of all of the features that will no longer be supported if you revert to a basic license. @@ -42,7 +42,7 @@ file that you install in {kib} or by using the TIP: If you are using a basic or trial license, {security-features} are disabled by default. In all other licenses, {security-features} are enabled by default; -you must secure the {stack} or disable the {security-features}. +you must secure the {stack} or disable the {security-features}. [discrete] [[license-expiration]] @@ -97,7 +97,7 @@ cluster. and start {dfeeds} are disabled. * All started {dfeeds} are stopped. * All open {anomaly-jobs} are closed. -* APIs to create and start {dfanalytics-jobs} are disabled. +* APIs to create and start {dfanalytics-jobs} are disabled. * Existing {anomaly-job} and {dfanalytics-job} results continue to be available by using {kib} or APIs. diff --git a/docs/management/managing-remote-clusters.asciidoc b/docs/management/managing-remote-clusters.asciidoc index a776cdf0334cb..6b69cfef5b768 100644 --- a/docs/management/managing-remote-clusters.asciidoc +++ b/docs/management/managing-remote-clusters.asciidoc @@ -1,8 +1,8 @@ [[working-remote-clusters]] -== Working with remote clusters +== Remote Clusters -{kib} *Management* provides user interfaces for working with data from remote -clusters and managing the {ccr} process. You can replicate indices from a +{kib} *Management* provides user interfaces for working with data from remote +clusters and managing the {ccr} process. You can replicate indices from a leader remote cluster to a follower index in a local cluster. The local follower indices can be used to provide remote backups for disaster recovery or for geo-proximite copies of data. @@ -14,51 +14,51 @@ Before using these features, you should be familiar with the following concepts: [float] [[managing-remote-clusters]] -== Managing remote clusters +== Managing remote clusters -*Remote clusters* helps you manage remote clusters for use with -{ccs} and {ccr}. You can add and remove remote clusters and check their connectivity. +*Remote clusters* helps you manage remote clusters for use with +{ccs} and {ccr}. You can add and remove remote clusters and check their connectivity. + +Before you use this feature, you should be familiar with the concept of +{ref}/modules-remote-clusters.html[remote clusters]. -Before you use this feature, you should be familiar with the concept of -{ref}/modules-remote-clusters.html[remote clusters]. - Go to *Management > Elasticsearch > Remote clusters* to create or manage your remotes. -To set up a new remote, click *Add a remote cluster*. Give the cluster a unique name -and define the seed nodes for cluster discovery. You can edit or remove your remote clusters +To set up a new remote, click *Add a remote cluster*. Give the cluster a unique name +and define the seed nodes for cluster discovery. You can edit or remove your remote clusters from the *Remote clusters* list view. [role="screenshot"] image::images/add_remote_cluster.png[][UI for adding a remote cluster] -Once a remote cluster is registered, you can use the tools under *{ccr-cap}* -to add and manage follower indices on the local cluster, and replicate data from +Once a remote cluster is registered, you can use the tools under *{ccr-cap}* +to add and manage follower indices on the local cluster, and replicate data from indices on the remote cluster based on an auto-follow index pattern. [float] [[managing-cross-cluster-replication]] == [xpack]#Managing {ccr}# -*{ccr-cap}* helps you create and manage the {ccr} process. -If you want to replicate data from existing indices, or set up -local followers on a case-by-case basis, go to *Follower indices*. -If you want to automatically detect and follow new indices when they are created -on a remote cluster, you can do so from *Auto-follow patterns*. +*{ccr-cap}* helps you create and manage the {ccr} process. +If you want to replicate data from existing indices, or set up +local followers on a case-by-case basis, go to *Follower indices*. +If you want to automatically detect and follow new indices when they are created +on a remote cluster, you can do so from *Auto-follow patterns*. -Creating an auto-follow pattern is useful when you have time-series data, like a logs index, on the -remote cluster that is created or rolled over on a daily basis. Once you have configured an -auto-follow pattern, any time a new index with a name that matches the pattern is +Creating an auto-follow pattern is useful when you have time-series data, like a logs index, on the +remote cluster that is created or rolled over on a daily basis. Once you have configured an +auto-follow pattern, any time a new index with a name that matches the pattern is created in the remote cluster, a follower index is automatically configured in the local cluster. -From the same view, you can also see a list of your saved auto-follow patterns for +From the same view, you can also see a list of your saved auto-follow patterns for a given remote cluster, and monitor whether the replication is active. Before you use these features, you should be familiar with the following concepts: -* {ref}/ccr-requirements.html[Requirements for leader indices] +* {ref}/ccr-requirements.html[Requirements for leader indices] * {ref}/ccr-auto-follow.html[Automatically following indices] -To get started, go to *Management > Elasticsearch > {ccr-cap}*. +To get started, go to *Management > Elasticsearch > {ccr-cap}*. [role="screenshot"] image::images/auto_follow_pattern.png[][UI for adding an auto-follow pattern] diff --git a/docs/management/managing-saved-objects.asciidoc b/docs/management/managing-saved-objects.asciidoc index 2daa4cf789f2a..a92a6ae4bdc09 100644 --- a/docs/management/managing-saved-objects.asciidoc +++ b/docs/management/managing-saved-objects.asciidoc @@ -1,9 +1,9 @@ [[managing-saved-objects]] -== Saved objects +== Saved Objects -*Saved Objects* helps you keep track of and manage your saved objects. These objects +The *Saved Objects* UI helps you keep track of and manage your saved objects. These objects store data for later use, including dashboards, visualizations, maps, index patterns, -Canvas workpads, and more. +Canvas workpads, and more. To get started, go to *Management > {kib} > Saved Objects*. With this UI, you can: @@ -23,8 +23,8 @@ image::images/management-saved-objects.png[Saved Objects] * To view and edit an object in its associated application, click the object title. -* To show objects that use this object, so you know the -impact of deleting it, click the actions icon image:images/actions_icon.png[Actions icon] +* To show objects that use this object, so you know the +impact of deleting it, click the actions icon image:images/actions_icon.png[Actions icon] and select *Relationships*. * To delete one or more objects, select their checkboxes, and then click *Delete*. @@ -33,19 +33,19 @@ and select *Relationships*. [[managing-saved-objects-export-objects]] === Import and export -Using the import and export commands, you can move objects between different -{kib} instances. This action is useful when you -have multiple environments for development and production. -Import and export also work well when you have a large number -of objects to update and want to batch the process. +Using the import and export commands, you can move objects between different +{kib} instances. This action is useful when you +have multiple environments for development and production. +Import and export also work well when you have a large number +of objects to update and want to batch the process. [float] ==== Import -You can import multiple objects in a single operation. Click *Import* and -navigate to the NDJSON file that -represents the objects to import. By default, +You can import multiple objects in a single operation. Click *Import* and +navigate to the NDJSON file that +represents the objects to import. By default, saved objects already in {kib} are overwritten. [float] @@ -56,7 +56,7 @@ You have two options for exporting saved objects. * Select the checkboxes of objects that you want to export, and then click *Export*. * Click *Export x objects*, and export objects by type. -This action creates an NDJSON with all your saved objects. By default, +This action creates an NDJSON with all your saved objects. By default, the NDJSON includes related objects. Exported dashboards include their associated index patterns. [float] @@ -78,9 +78,9 @@ use the <> inste === Advanced editing Some objects offer an advanced *Edit* page for modifying the object definition. -To open the page, click the actions icon image:images/actions_icon.png[Actions icon] -and select *Inspect*. -You can change the object title, add a description, and modify +To open the page, click the actions icon image:images/actions_icon.png[Actions icon] +and select *Inspect*. +You can change the object title, add a description, and modify the JSON that defines the object properties. If you access an object whose index has been deleted, you can: @@ -90,7 +90,7 @@ If you access an object whose index has been deleted, you can: * Change the index name in the object's `reference` array to point to an existing index pattern. This is useful if the index you were working with has been renamed. -WARNING: Validation is not performed for object properties. Submitting an invalid -change will render the object unusable. A more failsafe approach is to use -*Discover*, *Visualize*, or *Dashboard* to create new objects instead of +WARNING: Validation is not performed for object properties. Submitting an invalid +change will render the object unusable. A more failsafe approach is to use +*Discover*, *Visualize*, or *Dashboard* to create new objects instead of directly editing an existing one. diff --git a/docs/management/rollups/create_and_manage_rollups.asciidoc b/docs/management/rollups/create_and_manage_rollups.asciidoc index 06983c01f926d..b07f075f88032 100644 --- a/docs/management/rollups/create_and_manage_rollups.asciidoc +++ b/docs/management/rollups/create_and_manage_rollups.asciidoc @@ -1,14 +1,14 @@ [role="xpack"] [[data-rollups]] -== Rollup jobs +== Rollup Jobs -A rollup job is a periodic task that aggregates data from indices specified -by an index pattern and rolls it into a new index. Rollup indices are a good way to -compactly store months or years of historical +A rollup job is a periodic task that aggregates data from indices specified +by an index pattern, and then rolls it into a new index. Rollup indices are a good way to +compactly store months or years of historical data for use in visualizations and reports. -You’ll find *Rollup Jobs* under *Management > Elasticsearch*. With this UI, +You’ll find *Rollup Jobs* under *Management > Elasticsearch*. With this UI, you can: * <> @@ -17,22 +17,22 @@ you can: [role="screenshot"] image::images/management_rollup_list.png[][List of currently active rollup jobs] -Before using this feature, you should be familiar with how rollups work. -{ref}/xpack-rollup.html[Rolling up historical data] is a good source for more detailed information. +Before using this feature, you should be familiar with how rollups work. +{ref}/xpack-rollup.html[Rolling up historical data] is a good source for more detailed information. [float] [[create-and-manage-rollup-job]] === Create a rollup job -{kib} makes it easy for you to create a rollup job by walking you through -the process. You fill in the name, data flow, and how often you want to roll -up the data. Then you define a date histogram aggregation for the rollup job -and optionally terms, histogram, and metrics aggregations. +{kib} makes it easy for you to create a rollup job by walking you through +the process. You fill in the name, data flow, and how often you want to roll +up the data. Then you define a date histogram aggregation for the rollup job +and optionally define terms, histogram, and metrics aggregations. -When defining the index pattern, you must enter a name that is different than -the output rollup index. Otherwise, the job -will attempt to capture the data in the rollup index. For example, if your index pattern is `metricbeat-*`, -you can name your rollup index `rollup-metricbeat`, but not `metricbeat-rollup`. +When defining the index pattern, you must enter a name that is different than +the output rollup index. Otherwise, the job +will attempt to capture the data in the rollup index. For example, if your index pattern is `metricbeat-*`, +you can name your rollup index `rollup-metricbeat`, but not `metricbeat-rollup`. [role="screenshot"] image::images/management_create_rollup_job.png[][Wizard that walks you through creation of a rollup job] @@ -41,38 +41,38 @@ image::images/management_create_rollup_job.png[][Wizard that walks you through c [[manage-rollup-job]] === Start, stop, and delete rollup jobs -Once you’ve saved a rollup job, you’ll see it the *Rollup Jobs* overview page, -where you can drill down for further investigation. The *Manage* menu in +Once you’ve saved a rollup job, you’ll see it the *Rollup Jobs* overview page, +where you can drill down for further investigation. The *Manage* menu in the lower right enables you to start, stop, and delete the rollup job. You must first stop a rollup job before deleting it. [role="screenshot"] image::images/management_rollup_job_details.png[][Rollup job details] -You can’t change a rollup job after you’ve created it. To select additional fields -or redefine terms, you must delete the existing job, and then create a new one -with the updated specifications. Be sure to use a different name for the new rollup -job—reusing the same name can lead to problems with mismatched job configurations. -You can read more at {ref}/rollup-job-config.html[rollup job configuration]. +You can’t change a rollup job after you’ve created it. To select additional fields +or redefine terms, you must delete the existing job, and then create a new one +with the updated specifications. Be sure to use a different name for the new rollup +job—reusing the same name can lead to problems with mismatched job configurations. +You can read more at {ref}/rollup-job-config.html[rollup job configuration]. [float] === Try it: Create and visualize rolled up data -This example creates a rollup job to capture log data from sample web logs. +This example creates a rollup job to capture log data from sample web logs. To follow along, add the <>. In this example, you want data that is older than 7 days in the target index pattern `kibana_sample_data_logs` -to roll up once a day into the index `rollup_logstash`. You’ll bucket the -rolled up data on an hourly basis, using 60m for the time bucket configuration. +to roll up once a day into the index `rollup_logstash`. You’ll bucket the +rolled up data on an hourly basis, using 60m for the time bucket configuration. This allows for more granular queries, such as 2h and 12h. [float] ==== Create the rollup job -As you walk through the *Create rollup job* UI, enter the data shown in -the table below. The terms, histogram, and metrics fields reflect -the key information to retain in the rolled up data: where visitors are from (geo.src), -what operating system they are using (machine.os.keyword), +As you walk through the *Create rollup job* UI, enter the data shown in +the table below. The terms, histogram, and metrics fields reflect +the key information to retain in the rolled up data: where visitors are from (geo.src), +what operating system they are using (machine.os.keyword), and how much data is being sent (bytes). |=== @@ -118,31 +118,28 @@ and how much data is being sent (bytes). |=== -You can now use the rolled up data for analysis at a fraction of the storage cost -of the original index. The original data can live side by side with the new +You can now use the rolled up data for analysis at a fraction of the storage cost +of the original index. The original data can live side by side with the new rollup index, or you can remove or archive it using <>. [float] ==== Visualize the rolled up data -Your next step is to visualize your rolled up data in a vertical bar chart. +Your next step is to visualize your rolled up data in a vertical bar chart. Most visualizations support rolled up data, with the exception of Timelion, TSVB, and Vega visualizations. -Using the information from the example rollup configuration described above, -you can use `rollup_logstash` to match the rolled up index pattern, -and `kibana_sample_data_logs` to match the index pattern for raw data. -The notation for a combination index pattern with both raw and rolled up data +Using the information from the example rollup configuration described above, +you can use `rollup_logstash` to match the rolled up index pattern, +and `kibana_sample_data_logs` to match the index pattern for raw data. +The notation for a combination index pattern with both raw and rolled up data is `rollup_logstash,kibana_sample_data_logs`. [role="screenshot"] image::images/management_rollup_job_vis.png[][Visualization of rolled up data] -You can then create a dashboard that contains visualizations of the rolled up +You can then create a dashboard that contains visualizations of the rolled up data, raw data, or both. See <> for more information. [role="screenshot"] image::images/management_rollup_job_dashboard.png[][Dashboard with rolled up data] - - - diff --git a/docs/setup/install/targz.asciidoc b/docs/setup/install/targz.asciidoc index d2143f39fba50..31970888a976b 100644 --- a/docs/setup/install/targz.asciidoc +++ b/docs/setup/install/targz.asciidoc @@ -1,14 +1,14 @@ [[targz]] -=== Install Kibana with `.tar.gz` +=== Install {kib} from archive on Linux or MacOS Kibana is provided for Linux and Darwin as a `.tar.gz` package. These packages are the easiest formats to use when trying out Kibana. -These packages are free to use under the Elastic license. They contain open -source and free commercial features and access to paid commercial features. -{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the -paid commercial features. See the -https://www.elastic.co/subscriptions[Subscriptions] page for information about +These packages are free to use under the Elastic license. They contain open +source and free commercial features and access to paid commercial features. +{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the +paid commercial features. See the +https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. The latest stable version of Kibana can be found on the @@ -47,6 +47,27 @@ endif::[] [[install-darwin64]] ==== Download and install the Darwin package +[IMPORTANT] +.macOS Gatekeeper warnings +==== +Apple's rollout of stricter notarization requirements affected the notarization +of the {version} {kib} artifacts. If macOS Catalina displays a dialog when you +first run {kib} that interrupts it, you will need to take an action to allow it +to run. + +To prevent Gatekeeper checks on the {kib} files, run the following command on the +downloaded `.tar.gz` archive or the directory to which was extracted: +[source,sh] +---- +xattr -d -r com.apple.quarantine +---- + +Alternatively, you can add a security override if a Gatekeeper popup appears by +following the instructions in the _How to open an app that hasn’t been notarized +or is from an unidentified developer_ section of +https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. +==== + ifeval::["{release-state}"=="unreleased"] Version {version} of Kibana has not yet been released. @@ -68,9 +89,9 @@ cd kibana-{version}-darwin-x86_64/ <2> `kibana-{version}-darwin-x86_64.tar.gz: OK`. <2> This directory is known as `$KIBANA_HOME`. -Alternatively, you can download the following package, which contains only +Alternatively, you can download the following package, which contains only features that are available under the Apache 2.0 license: -https://artifacts.elastic.co/downloads/kibana/kibana-oss-{version}-darwin-x86_64.tar.gz +https://artifacts.elastic.co/downloads/kibana/kibana-oss-{version}-darwin-x86_64.tar.gz endif::[] diff --git a/docs/setup/upgrade.asciidoc b/docs/setup/upgrade.asciidoc index 8c03032bb8ac3..982f1167f3871 100644 --- a/docs/setup/upgrade.asciidoc +++ b/docs/setup/upgrade.asciidoc @@ -50,7 +50,7 @@ instructions. [[upgrade-6x]] === Upgrading from 6.x -The recommended path is to upgrade to 6.7 before upgrading to 7.0. This makes it +The recommended path is to upgrade to 6.8 before upgrading to 7.0. This makes it easier to identify the required changes, and enables you to use the Upgrade Assistant to prepare for your upgrade to 7.0. @@ -59,11 +59,11 @@ dashboards is supported. [float] [[upgrade-67]] -=== Upgrading from 6.7 -To help you prepare for your upgrade to 7.0, 6.7 includes an https://www.elastic.co/guide/en/kibana/6.7/upgrade-assistant.html[Upgrade Assistant] -To access the assistant, go to *Management > 7.0 Upgrade Assistant*. +=== Upgrading from 6.8 +To help you prepare for your upgrade to 7.0, 6.8 includes an https://www.elastic.co/guide/en/kibana/6.8/upgrade-assistant.html[Upgrade Assistant] +To access the assistant, go to *Management > 7.0 Upgrade Assistant*. -After you have addressed any issues that were identified by the Upgrade +After you have addressed any issues that were identified by the Upgrade Assistant, <>. diff --git a/docs/siem/images/detections-ui.png b/docs/siem/images/detections-ui.png new file mode 100644 index 0000000000000..3139ffea0767d Binary files /dev/null and b/docs/siem/images/detections-ui.png differ diff --git a/docs/siem/images/hosts-ui.png b/docs/siem/images/hosts-ui.png index 2569df8f419b8..be9fd29246b51 100644 Binary files a/docs/siem/images/hosts-ui.png and b/docs/siem/images/hosts-ui.png differ diff --git a/docs/siem/images/network-ui.png b/docs/siem/images/network-ui.png index 406ac854cd0a2..de8ce89273a02 100644 Binary files a/docs/siem/images/network-ui.png and b/docs/siem/images/network-ui.png differ diff --git a/docs/siem/images/overview-ui.png b/docs/siem/images/overview-ui.png index a34b2fea061c9..6ac02104d6123 100644 Binary files a/docs/siem/images/overview-ui.png and b/docs/siem/images/overview-ui.png differ diff --git a/docs/siem/siem-ui.asciidoc b/docs/siem/siem-ui.asciidoc index 7294cfbc414f4..f01575a21b9f6 100644 --- a/docs/siem/siem-ui.asciidoc +++ b/docs/siem/siem-ui.asciidoc @@ -33,6 +33,23 @@ investigation. [role="screenshot"] image::siem/images/network-ui.png[] +[float] +[[detections-ui]] +=== Detections + +The Detections feature automatically searches for threats and creates +signals when they are detected. Signal detection rules define the conditions +for creating signals. The SIEM app comes with prebuilt rules that search for +suspicious activity on your network and hosts. Additionally, you can +create your own rules. + +See {siem-guide}/detection-engine-overview.html[Detections] in the SIEM +Guide for information on managing detection rules and signals via the UI +or the Detections API. + +[role="screenshot"] +image::siem/images/detections-ui.png[] + [float] [[timelines-ui]] === Timeline diff --git a/docs/user/index.asciidoc b/docs/user/index.asciidoc index ebe6c10c49872..3911d57e05c9a 100644 --- a/docs/user/index.asciidoc +++ b/docs/user/index.asciidoc @@ -38,14 +38,6 @@ include::monitoring/index.asciidoc[] include::management.asciidoc[] -include::{kib-repo-dir}/spaces/index.asciidoc[] - -include::security/index.asciidoc[] - -include::{kib-repo-dir}/management/watcher-ui/index.asciidoc[] - -include::{kib-repo-dir}/management/upgrade-assistant/index.asciidoc[] - include::reporting/index.asciidoc[] include::api.asciidoc[] diff --git a/docs/user/management.asciidoc b/docs/user/management.asciidoc index 2c41d0072fe5b..1c55ffc73ca72 100644 --- a/docs/user/management.asciidoc +++ b/docs/user/management.asciidoc @@ -3,17 +3,115 @@ [partintro] -- -The Management application is where you perform your runtime configuration of -Kibana, including both the initial setup and ongoing configuration of index -patterns, advanced settings that tweak the behaviors of Kibana itself, and -the various "objects" that you can save throughout Kibana such as searches, -visualizations, and dashboards. +*Management* is home to UIs for managing all things Elastic Stack— +indices, clusters, licenses, UI settings, index patterns, spaces, and more. + +[float] +[[manage-Elasticsearch]] +== Manage {es} + +[cols="50, 50"] +|=== + +a| <> + +Replicate indices on a remote cluster and copy them to a follower index on a local cluster. +This is important for +disaster recovery. It also keeps data local for faster queries. + +| <> + +Create a policy for defining the lifecycle of an index as it ages +through the hot, warm, cold, and delete phases. +Such policies help you control operation costs +because you can put data in different resource tiers. + +a| <> + +View index settings, mappings, and statistics and perform operations, such as refreshing, +flushing, and clearing the cache. Practicing good index management ensures +that your data is stored cost effectively. + +| <> + +View the status of your license, start a trial, or install a new license. For +the full list of features that are included in your license, +see the https://www.elastic.co/subscriptions[subscription page]. + +| <> + +Manage your remote clusters for use with cross-cluster search and cross-cluster replication. +You can add and remove remote clusters, and check their connectivity. + +| <> + +Create a job that periodically aggregates data from one or more indices, and then +rolls it into a new, compact index. Rollup indices are a good way to store months or +years of historical data in combination with your raw data. + +| <> + +Define a policy that creates, schedules, and automatically deletes snapshots to ensure that you +have backups of your cluster in case something goes wrong. + +| {ref}/transforms.html[*Transforms*] + +Use transforms to pivot existing {es} indices into summarized or entity-centric indices. + +| <> + +Identify the issues that you need to address before upgrading to the +next major version of {es}, and then reindex, if needed. + +| <> + +Detect changes in your data by creating, managing, and monitoring alerts. +For example, create an alert when the maximum total CPU usage on a machine goes +above a certain percentage. + +|=== + +[float] +[[manage-kibana]] +== Manage {kib} + +[cols="50, 50"] +|=== + +a| <> + +Customize {kib} to suit your needs. Change the format for displaying dates, turn on dark mode, +set the timespan for notification messages, and much more. + +| <> + +Create and manage the index patterns that help you retrieve your data from {es}. + +| <> + +Monitor the generation of reports—PDF, PNG, and CSV—and download reports that you previously generated. +A report can contain a dashboard, visualization, saved search, or Canvas workpad. + +| <> + +Copy, edit, delete, import, and export your saved objects. +These include dashboards, visualizations, maps, index patterns, Canvas workpads, and more. + +| <> + +Create spaces to organize your dashboards and other saved objects into categories. +A space is isolated from all other spaces, +so you can tailor it to your needs without impacting others. + +|   + +|=== -- -include::{kib-repo-dir}/management/managing-licenses.asciidoc[] +include::{kib-repo-dir}/management/advanced-options.asciidoc[] -include::{kib-repo-dir}/management/rollups/create_and_manage_rollups.asciidoc[] +include::{kib-repo-dir}/management/managing-beats.asciidoc[] include::{kib-repo-dir}/management/index-lifecycle-policies/intro-to-lifecycle-policies.asciidoc[] @@ -25,16 +123,24 @@ include::{kib-repo-dir}/management/index-lifecycle-policies/add-policy-to-index. include::{kib-repo-dir}/management/index-lifecycle-policies/example-index-lifecycle-policy.asciidoc[] +include::{kib-repo-dir}/management/managing-indices.asciidoc[] + include::{kib-repo-dir}/management/managing-fields.asciidoc[] -include::{kib-repo-dir}/management/managing-indices.asciidoc[] +include::{kib-repo-dir}/management/managing-licenses.asciidoc[] -include::{kib-repo-dir}/management/advanced-options.asciidoc[] +include::{kib-repo-dir}/management/managing-remote-clusters.asciidoc[] -include::{kib-repo-dir}/management/managing-saved-objects.asciidoc[] +include::{kib-repo-dir}/management/rollups/create_and_manage_rollups.asciidoc[] -include::{kib-repo-dir}/management/managing-beats.asciidoc[] +include::{kib-repo-dir}/management/managing-saved-objects.asciidoc[] -include::{kib-repo-dir}/management/managing-remote-clusters.asciidoc[] +include::security/index.asciidoc[] include::{kib-repo-dir}/management/snapshot-restore/index.asciidoc[] + +include::{kib-repo-dir}/spaces/index.asciidoc[] + +include::{kib-repo-dir}/management/upgrade-assistant/index.asciidoc[] + +include::{kib-repo-dir}/management/watcher-ui/index.asciidoc[] diff --git a/package.json b/package.json index f9a3bfd99b109..539d3a067665f 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "@babel/core": "^7.5.5", "@babel/register": "^7.7.0", "@elastic/apm-rum": "^4.6.0", - "@elastic/charts": "^16.1.0", + "@elastic/charts": "^17.0.2", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "7.6.0", "@elastic/eui": "18.3.0", @@ -144,13 +144,13 @@ "@types/react-grid-layout": "^0.16.7", "@types/recompose": "^0.30.5", "JSONStream": "1.3.5", - "abortcontroller-polyfill": "^1.3.0", + "abort-controller": "^3.0.0", "angular": "^1.7.9", - "angular-aria": "^1.7.8", + "angular-aria": "^1.7.9", "angular-elastic": "^2.5.1", "angular-recursion": "^1.0.5", - "angular-route": "^1.7.8", - "angular-sanitize": "^1.7.8", + "angular-route": "^1.7.9", + "angular-sanitize": "^1.7.9", "angular-sortable-view": "^0.0.17", "autoprefixer": "9.6.1", "babel-loader": "^8.0.6", @@ -262,7 +262,7 @@ "style-loader": "0.23.1", "symbol-observable": "^1.2.0", "tar": "4.4.13", - "terser-webpack-plugin": "^2.1.2", + "terser-webpack-plugin": "^2.3.4", "thread-loader": "^2.1.3", "tinygradient": "0.4.3", "tinymath": "1.2.1", @@ -380,7 +380,7 @@ "@types/zen-observable": "^0.8.0", "@typescript-eslint/eslint-plugin": "^2.15.0", "@typescript-eslint/parser": "^2.15.0", - "angular-mocks": "^1.7.8", + "angular-mocks": "^1.7.9", "archiver": "^3.1.1", "axe-core": "^3.3.2", "babel-eslint": "^10.0.3", @@ -476,7 +476,7 @@ "strip-ansi": "^3.0.1", "supertest": "^3.1.0", "supertest-as-promised": "^4.0.2", - "tree-kill": "^1.2.1", + "tree-kill": "^1.2.2", "typescript": "3.7.2", "typings-tester": "^0.3.2", "vinyl-fs": "^3.0.3", @@ -485,7 +485,7 @@ "zlib": "^1.0.5" }, "engines": { - "node": "10.18.0", + "node": "10.19.0", "yarn": "^1.21.1" } } diff --git a/packages/kbn-dev-utils/package.json b/packages/kbn-dev-utils/package.json index cef29f33962cd..bea153d0a672b 100644 --- a/packages/kbn-dev-utils/package.json +++ b/packages/kbn-dev-utils/package.json @@ -18,7 +18,7 @@ "load-json-file": "^6.2.0", "moment": "^2.24.0", "rxjs": "^6.5.3", - "tree-kill": "^1.2.1", + "tree-kill": "^1.2.2", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/kbn-es/package.json b/packages/kbn-es/package.json index cb501dab3ddb7..f9d7bffed1e22 100644 --- a/packages/kbn-es/package.json +++ b/packages/kbn-es/package.json @@ -17,7 +17,7 @@ "node-fetch": "^2.6.0", "simple-git": "^1.91.0", "tar-fs": "^1.16.3", - "tree-kill": "^1.2.1", + "tree-kill": "^1.2.2", "yauzl": "^2.10.0" } } diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 8bded9d403c21..f3e401bedcef3 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -94,7 +94,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; }); -/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(703); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(705); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); @@ -152,7 +152,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _commands__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(689); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(690); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(34); /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -2507,8 +2507,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "commands", function() { return commands; }); /* harmony import */ var _bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18); /* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(686); -/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(687); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(687); +/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(688); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -36382,15 +36382,24 @@ var spawn = childProcess.spawn; var exec = childProcess.exec; module.exports = function (pid, signal, callback) { + if (typeof signal === 'function' && callback === undefined) { + callback = signal; + signal = undefined; + } + + pid = parseInt(pid); + if (Number.isNaN(pid)) { + if (callback) { + return callback(new Error("pid must be a number")); + } else { + throw new Error("pid must be a number"); + } + } + var tree = {}; var pidsToProcess = {}; tree[pid] = []; pidsToProcess[pid] = 1; - - if (typeof signal === 'function' && callback === undefined) { - callback = signal; - signal = undefined; - } switch (process.platform) { case 'win32': @@ -46624,9 +46633,11 @@ function range(a, b, str) { try { var util = __webpack_require__(29); + /* istanbul ignore next */ if (typeof util.inherits !== 'function') throw ''; module.exports = util.inherits; } catch (e) { + /* istanbul ignore next */ module.exports = __webpack_require__(510); } @@ -46638,24 +46649,28 @@ try { if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) + } }; } else { // old school shim for old browsers module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } } } @@ -56566,12 +56581,18 @@ function runScriptInPackageStreaming(script, args, pkg) { }); } async function yarnWorkspacesInfo(directory) { - const workspacesInfo = await Object(_child_process__WEBPACK_IMPORTED_MODULE_0__["spawn"])('yarn', ['workspaces', 'info', '--json'], { + const { + stdout + } = await Object(_child_process__WEBPACK_IMPORTED_MODULE_0__["spawn"])('yarn', ['--json', 'workspaces', 'info'], { cwd: directory, stdio: 'pipe' }); - const stdout = JSON.parse(workspacesInfo.stdout); - return JSON.parse(stdout.data); + + try { + return JSON.parse(JSON.parse(stdout).data); + } catch (error) { + throw new Error(`'yarn workspaces info --json' produced unexpected output: \n${stdout}`); + } } /***/ }), @@ -68970,7 +68991,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(588); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(675); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(676); /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); @@ -69078,13 +69099,13 @@ const CleanCommand = { const {promisify} = __webpack_require__(29); const path = __webpack_require__(16); const globby = __webpack_require__(589); -const isGlob = __webpack_require__(601); -const slash = __webpack_require__(662); -const gracefulFs = __webpack_require__(664); -const isPathCwd = __webpack_require__(668); -const isPathInside = __webpack_require__(669); -const rimraf = __webpack_require__(670); -const pMap = __webpack_require__(671); +const isGlob = __webpack_require__(606); +const slash = __webpack_require__(667); +const gracefulFs = __webpack_require__(22); +const isPathCwd = __webpack_require__(669); +const isPathInside = __webpack_require__(670); +const rimraf = __webpack_require__(671); +const pMap = __webpack_require__(672); const rimrafP = promisify(rimraf); @@ -69206,11 +69227,11 @@ module.exports.sync = (patterns, {force, dryRun, cwd = process.cwd(), ...options const fs = __webpack_require__(23); const arrayUnion = __webpack_require__(590); const merge2 = __webpack_require__(591); -const glob = __webpack_require__(502); -const fastGlob = __webpack_require__(592); -const dirGlob = __webpack_require__(658); -const gitignore = __webpack_require__(660); -const {FilterStream, UniqueStream} = __webpack_require__(663); +const glob = __webpack_require__(592); +const fastGlob = __webpack_require__(597); +const dirGlob = __webpack_require__(663); +const gitignore = __webpack_require__(665); +const {FilterStream, UniqueStream} = __webpack_require__(668); const DEFAULT_FILTER = () => false; @@ -69512,5704 +69533,7286 @@ function pauseStreams (streams, options) { /* 592 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - -const taskManager = __webpack_require__(593); -const async_1 = __webpack_require__(621); -const stream_1 = __webpack_require__(654); -const sync_1 = __webpack_require__(655); -const settings_1 = __webpack_require__(657); -const utils = __webpack_require__(594); -function FastGlob(source, options) { - try { - assertPatternsInput(source); - } - catch (error) { - return Promise.reject(error); - } - const works = getWorks(source, async_1.default, options); - return Promise.all(works).then(utils.array.flatten); -} -(function (FastGlob) { - function sync(source, options) { - assertPatternsInput(source); - const works = getWorks(source, sync_1.default, options); - return utils.array.flatten(works); - } - FastGlob.sync = sync; - function stream(source, options) { - assertPatternsInput(source); - const works = getWorks(source, stream_1.default, options); - /** - * The stream returned by the provider cannot work with an asynchronous iterator. - * To support asynchronous iterators, regardless of the number of tasks, we always multiplex streams. - * This affects performance (+25%). I don't see best solution right now. - */ - return utils.stream.merge(works); - } - FastGlob.stream = stream; - function generateTasks(source, options) { - assertPatternsInput(source); - const patterns = [].concat(source); - const settings = new settings_1.default(options); - return taskManager.generate(patterns, settings); - } - FastGlob.generateTasks = generateTasks; -})(FastGlob || (FastGlob = {})); -function getWorks(source, _Provider, options) { - const patterns = [].concat(source); - const settings = new settings_1.default(options); - const tasks = taskManager.generate(patterns, settings); - const provider = new _Provider(settings); - return tasks.map(provider.read, provider); -} -function assertPatternsInput(source) { - if ([].concat(source).every(isString)) { - return; - } - throw new TypeError('Patterns must be a string or an array of strings'); -} -function isString(source) { - /* tslint:disable-next-line strict-type-predicates */ - return typeof source === 'string'; -} -module.exports = FastGlob; +// Approach: +// +// 1. Get the minimatch set +// 2. For each pattern in the set, PROCESS(pattern, false) +// 3. Store matches per-set, then uniq them +// +// PROCESS(pattern, inGlobStar) +// Get the first [n] items from pattern that are all strings +// Join these together. This is PREFIX. +// If there is no more remaining, then stat(PREFIX) and +// add to matches if it succeeds. END. +// +// If inGlobStar and PREFIX is symlink and points to dir +// set ENTRIES = [] +// else readdir(PREFIX) as ENTRIES +// If fail, END +// +// with ENTRIES +// If pattern[n] is GLOBSTAR +// // handle the case where the globstar match is empty +// // by pruning it out, and testing the resulting pattern +// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) +// // handle other cases. +// for ENTRY in ENTRIES (not dotfiles) +// // attach globstar + tail onto the entry +// // Mark that this entry is a globstar match +// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) +// +// else // not globstar +// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) +// Test ENTRY against pattern[n] +// If fails, continue +// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) +// +// Caveat: +// Cache all stats and readdirs results to minimize syscall. Since all +// we ever care about is existence and directory-ness, we can just keep +// `true` for files, and [children,...] for directories, or `false` for +// things that don't exist. +module.exports = glob -/***/ }), -/* 593 */ -/***/ (function(module, exports, __webpack_require__) { +var fs = __webpack_require__(23) +var rp = __webpack_require__(503) +var minimatch = __webpack_require__(505) +var Minimatch = minimatch.Minimatch +var inherits = __webpack_require__(593) +var EE = __webpack_require__(379).EventEmitter +var path = __webpack_require__(16) +var assert = __webpack_require__(30) +var isAbsolute = __webpack_require__(511) +var globSync = __webpack_require__(595) +var common = __webpack_require__(596) +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var inflight = __webpack_require__(514) +var util = __webpack_require__(29) +var childrenIgnored = common.childrenIgnored +var isIgnored = common.isIgnored -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(594); -function generate(patterns, settings) { - const positivePatterns = getPositivePatterns(patterns); - const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); - /** - * When the `caseSensitiveMatch` option is disabled, all patterns must be marked as dynamic, because we cannot check - * filepath directly (without read directory). - */ - const staticPatterns = !settings.caseSensitiveMatch ? [] : positivePatterns.filter(utils.pattern.isStaticPattern); - const dynamicPatterns = !settings.caseSensitiveMatch ? positivePatterns : positivePatterns.filter(utils.pattern.isDynamicPattern); - const staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false); - const dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true); - return staticTasks.concat(dynamicTasks); -} -exports.generate = generate; -function convertPatternsToTasks(positive, negative, dynamic) { - const positivePatternsGroup = groupPatternsByBaseDirectory(positive); - // When we have a global group – there is no reason to divide the patterns into independent tasks. - // In this case, the global task covers the rest. - if ('.' in positivePatternsGroup) { - const task = convertPatternGroupToTask('.', positive, negative, dynamic); - return [task]; - } - return convertPatternGroupsToTasks(positivePatternsGroup, negative, dynamic); -} -exports.convertPatternsToTasks = convertPatternsToTasks; -function getPositivePatterns(patterns) { - return utils.pattern.getPositivePatterns(patterns); -} -exports.getPositivePatterns = getPositivePatterns; -function getNegativePatternsAsPositive(patterns, ignore) { - const negative = utils.pattern.getNegativePatterns(patterns).concat(ignore); - const positive = negative.map(utils.pattern.convertToPositivePattern); - return positive; -} -exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive; -function groupPatternsByBaseDirectory(patterns) { - return patterns.reduce((collection, pattern) => { - const base = utils.pattern.getBaseDirectory(pattern); - if (base in collection) { - collection[base].push(pattern); - } - else { - collection[base] = [pattern]; - } - return collection; - }, {}); -} -exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; -function convertPatternGroupsToTasks(positive, negative, dynamic) { - return Object.keys(positive).map((base) => { - return convertPatternGroupToTask(base, positive[base], negative, dynamic); - }); -} -exports.convertPatternGroupsToTasks = convertPatternGroupsToTasks; -function convertPatternGroupToTask(base, positive, negative, dynamic) { - return { - dynamic, - positive, - negative, - base, - patterns: [].concat(positive, negative.map(utils.pattern.convertToNegativePattern)) - }; -} -exports.convertPatternGroupToTask = convertPatternGroupToTask; +var once = __webpack_require__(385) +function glob (pattern, options, cb) { + if (typeof options === 'function') cb = options, options = {} + if (!options) options = {} -/***/ }), -/* 594 */ -/***/ (function(module, exports, __webpack_require__) { + if (options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return globSync(pattern, options) + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const array = __webpack_require__(595); -exports.array = array; -const errno = __webpack_require__(596); -exports.errno = errno; -const fs = __webpack_require__(597); -exports.fs = fs; -const path = __webpack_require__(598); -exports.path = path; -const pattern = __webpack_require__(599); -exports.pattern = pattern; -const stream = __webpack_require__(620); -exports.stream = stream; + return new Glob(pattern, options, cb) +} +glob.sync = globSync +var GlobSync = glob.GlobSync = globSync.GlobSync -/***/ }), -/* 595 */ -/***/ (function(module, exports, __webpack_require__) { +// old api surface +glob.glob = glob -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function flatten(items) { - return items.reduce((collection, item) => [].concat(collection, item), []); -} -exports.flatten = flatten; +function extend (origin, add) { + if (add === null || typeof add !== 'object') { + return origin + } + var keys = Object.keys(add) + var i = keys.length + while (i--) { + origin[keys[i]] = add[keys[i]] + } + return origin +} -/***/ }), -/* 596 */ -/***/ (function(module, exports, __webpack_require__) { +glob.hasMagic = function (pattern, options_) { + var options = extend({}, options_) + options.noprocess = true -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function isEnoentCodeError(error) { - return error.code === 'ENOENT'; -} -exports.isEnoentCodeError = isEnoentCodeError; + var g = new Glob(pattern, options) + var set = g.minimatch.set + if (!pattern) + return false -/***/ }), -/* 597 */ -/***/ (function(module, exports, __webpack_require__) { + if (set.length > 1) + return true -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -class DirentFromStats { - constructor(name, stats) { - this.name = name; - this.isBlockDevice = stats.isBlockDevice.bind(stats); - this.isCharacterDevice = stats.isCharacterDevice.bind(stats); - this.isDirectory = stats.isDirectory.bind(stats); - this.isFIFO = stats.isFIFO.bind(stats); - this.isFile = stats.isFile.bind(stats); - this.isSocket = stats.isSocket.bind(stats); - this.isSymbolicLink = stats.isSymbolicLink.bind(stats); - } -} -function createDirentFromStats(name, stats) { - return new DirentFromStats(name, stats); -} -exports.createDirentFromStats = createDirentFromStats; + for (var j = 0; j < set[0].length; j++) { + if (typeof set[0][j] !== 'string') + return true + } + return false +} -/***/ }), -/* 598 */ -/***/ (function(module, exports, __webpack_require__) { +glob.Glob = Glob +inherits(Glob, EE) +function Glob (pattern, options, cb) { + if (typeof options === 'function') { + cb = options + options = null + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(16); -/** - * Designed to work only with simple paths: `dir\\file`. - */ -function unixify(filepath) { - return filepath.replace(/\\/g, '/'); -} -exports.unixify = unixify; -function makeAbsolute(cwd, filepath) { - return path.resolve(cwd, filepath); -} -exports.makeAbsolute = makeAbsolute; + if (options && options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return new GlobSync(pattern, options) + } + if (!(this instanceof Glob)) + return new Glob(pattern, options, cb) -/***/ }), -/* 599 */ -/***/ (function(module, exports, __webpack_require__) { + setopts(this, pattern, options) + this._didRealPath = false -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(16); -const globParent = __webpack_require__(600); -const isGlob = __webpack_require__(601); -const micromatch = __webpack_require__(603); -const GLOBSTAR = '**'; -function isStaticPattern(pattern) { - return !isDynamicPattern(pattern); -} -exports.isStaticPattern = isStaticPattern; -function isDynamicPattern(pattern) { - return isGlob(pattern, { strict: false }); -} -exports.isDynamicPattern = isDynamicPattern; -function convertToPositivePattern(pattern) { - return isNegativePattern(pattern) ? pattern.slice(1) : pattern; -} -exports.convertToPositivePattern = convertToPositivePattern; -function convertToNegativePattern(pattern) { - return '!' + pattern; -} -exports.convertToNegativePattern = convertToNegativePattern; -function isNegativePattern(pattern) { - return pattern.startsWith('!') && pattern[1] !== '('; -} -exports.isNegativePattern = isNegativePattern; -function isPositivePattern(pattern) { - return !isNegativePattern(pattern); -} -exports.isPositivePattern = isPositivePattern; -function getNegativePatterns(patterns) { - return patterns.filter(isNegativePattern); -} -exports.getNegativePatterns = getNegativePatterns; -function getPositivePatterns(patterns) { - return patterns.filter(isPositivePattern); -} -exports.getPositivePatterns = getPositivePatterns; -function getBaseDirectory(pattern) { - return globParent(pattern); -} -exports.getBaseDirectory = getBaseDirectory; -function hasGlobStar(pattern) { - return pattern.indexOf(GLOBSTAR) !== -1; -} -exports.hasGlobStar = hasGlobStar; -function endsWithSlashGlobStar(pattern) { - return pattern.endsWith('/' + GLOBSTAR); -} -exports.endsWithSlashGlobStar = endsWithSlashGlobStar; -function isAffectDepthOfReadingPattern(pattern) { - const basename = path.basename(pattern); - return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); -} -exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; -function getNaiveDepth(pattern) { - const base = getBaseDirectory(pattern); - const patternDepth = pattern.split('/').length; - const patternBaseDepth = base.split('/').length; - /** - * This is a hack for pattern that has no base directory. - * - * This is related to the `*\something\*` pattern. - */ - if (base === '.') { - return patternDepth - patternBaseDepth; - } - return patternDepth - patternBaseDepth - 1; -} -exports.getNaiveDepth = getNaiveDepth; -function getMaxNaivePatternsDepth(patterns) { - return patterns.reduce((max, pattern) => { - const depth = getNaiveDepth(pattern); - return depth > max ? depth : max; - }, 0); -} -exports.getMaxNaivePatternsDepth = getMaxNaivePatternsDepth; -function makeRe(pattern, options) { - return micromatch.makeRe(pattern, options); -} -exports.makeRe = makeRe; -function convertPatternsToRe(patterns, options) { - return patterns.map((pattern) => makeRe(pattern, options)); -} -exports.convertPatternsToRe = convertPatternsToRe; -function matchAny(entry, patternsRe) { - const filepath = entry.replace(/^\.[\\\/]/, ''); - return patternsRe.some((patternRe) => patternRe.test(filepath)); -} -exports.matchAny = matchAny; + // process each pattern in the minimatch set + var n = this.minimatch.set.length + // The matches are stored as {: true,...} so that + // duplicates are automagically pruned. + // Later, we do an Object.keys() on these. + // Keep them as a list so we can fill in when nonull is set. + this.matches = new Array(n) -/***/ }), -/* 600 */ -/***/ (function(module, exports, __webpack_require__) { + if (typeof cb === 'function') { + cb = once(cb) + this.on('error', cb) + this.on('end', function (matches) { + cb(null, matches) + }) + } -"use strict"; + var self = this + this._processing = 0 + this._emitQueue = [] + this._processQueue = [] + this.paused = false -var isGlob = __webpack_require__(601); -var pathPosixDirname = __webpack_require__(16).posix.dirname; -var isWin32 = __webpack_require__(11).platform() === 'win32'; + if (this.noprocess) + return this -var slash = '/'; -var backslash = /\\/g; -var enclosure = /[\{\[].*[\/]*.*[\}\]]$/; -var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; -var escaped = /\\([\*\?\|\[\]\(\)\{\}])/g; + if (n === 0) + return done() -module.exports = function globParent(str) { - // flip windows path separators - if (isWin32 && str.indexOf(slash) < 0) { - str = str.replace(backslash, slash); + var sync = true + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false, done) } + sync = false - // special case for strings ending in enclosure containing path separator - if (enclosure.test(str)) { - str += slash; + function done () { + --self._processing + if (self._processing <= 0) { + if (sync) { + process.nextTick(function () { + self._finish() + }) + } else { + self._finish() + } + } } +} - // preserves full path in case of trailing path separator - str += 'a'; +Glob.prototype._finish = function () { + assert(this instanceof Glob) + if (this.aborted) + return - // remove path parts that are globby - do { - str = pathPosixDirname(str); - } while (isGlob(str) || globby.test(str)); + if (this.realpath && !this._didRealpath) + return this._realpath() - // remove escape chars and return result - return str.replace(escaped, '$1'); -}; + common.finish(this) + this.emit('end', this.found) +} +Glob.prototype._realpath = function () { + if (this._didRealpath) + return -/***/ }), -/* 601 */ -/***/ (function(module, exports, __webpack_require__) { + this._didRealpath = true -/*! - * is-glob - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ + var n = this.matches.length + if (n === 0) + return this._finish() -var isExtglob = __webpack_require__(602); -var chars = { '{': '}', '(': ')', '[': ']'}; -var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; -var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; + var self = this + for (var i = 0; i < this.matches.length; i++) + this._realpathSet(i, next) -module.exports = function isGlob(str, options) { - if (typeof str !== 'string' || str === '') { - return false; + function next () { + if (--n === 0) + self._finish() } +} - if (isExtglob(str)) { - return true; - } +Glob.prototype._realpathSet = function (index, cb) { + var matchset = this.matches[index] + if (!matchset) + return cb() - var regex = strictRegex; - var match; + var found = Object.keys(matchset) + var self = this + var n = found.length - // optionally relax regex - if (options && options.strict === false) { - regex = relaxedRegex; - } + if (n === 0) + return cb() - while ((match = regex.exec(str))) { - if (match[2]) return true; - var idx = match.index + match[0].length; + var set = this.matches[index] = Object.create(null) + found.forEach(function (p, i) { + // If there's a problem with the stat, then it means that + // one or more of the links in the realpath couldn't be + // resolved. just return the abs value in that case. + p = self._makeAbs(p) + rp.realpath(p, self.realpathCache, function (er, real) { + if (!er) + set[real] = true + else if (er.syscall === 'stat') + set[p] = true + else + self.emit('error', er) // srsly wtf right here - // if an open bracket/brace/paren is escaped, - // set the index to the next closing character - var open = match[1]; - var close = open ? chars[open] : null; - if (open && close) { - var n = str.indexOf(close, idx); - if (n !== -1) { - idx = n + 1; + if (--n === 0) { + self.matches[index] = set + cb() } - } + }) + }) +} - str = str.slice(idx); - } - return false; -}; +Glob.prototype._mark = function (p) { + return common.mark(this, p) +} +Glob.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} -/***/ }), -/* 602 */ -/***/ (function(module, exports) { +Glob.prototype.abort = function () { + this.aborted = true + this.emit('abort') +} -/*! - * is-extglob - * - * Copyright (c) 2014-2016, Jon Schlinkert. - * Licensed under the MIT License. - */ +Glob.prototype.pause = function () { + if (!this.paused) { + this.paused = true + this.emit('pause') + } +} -module.exports = function isExtglob(str) { - if (typeof str !== 'string' || str === '') { - return false; +Glob.prototype.resume = function () { + if (this.paused) { + this.emit('resume') + this.paused = false + if (this._emitQueue.length) { + var eq = this._emitQueue.slice(0) + this._emitQueue.length = 0 + for (var i = 0; i < eq.length; i ++) { + var e = eq[i] + this._emitMatch(e[0], e[1]) + } + } + if (this._processQueue.length) { + var pq = this._processQueue.slice(0) + this._processQueue.length = 0 + for (var i = 0; i < pq.length; i ++) { + var p = pq[i] + this._processing-- + this._process(p[0], p[1], p[2], p[3]) + } + } } +} - var match; - while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { - if (match[2]) return true; - str = str.slice(match.index + match[0].length); +Glob.prototype._process = function (pattern, index, inGlobStar, cb) { + assert(this instanceof Glob) + assert(typeof cb === 'function') + + if (this.aborted) + return + + this._processing++ + if (this.paused) { + this._processQueue.push([pattern, index, inGlobStar, cb]) + return } - return false; -}; + //console.error('PROCESS %d', this._processing, pattern) + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. -/***/ }), -/* 603 */ -/***/ (function(module, exports, __webpack_require__) { + // see if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index, cb) + return -"use strict"; + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } -const util = __webpack_require__(29); -const braces = __webpack_require__(604); -const picomatch = __webpack_require__(614); -const utils = __webpack_require__(617); -const isEmptyString = val => typeof val === 'string' && (val === '' || val === './'); + var remain = pattern.slice(n) -/** - * Returns an array of strings that match one or more glob patterns. - * - * ```js - * const mm = require('micromatch'); - * // mm(list, patterns[, options]); - * - * console.log(mm(['a.js', 'a.txt'], ['*.js'])); - * //=> [ 'a.js' ] - * ``` - * @param {String|Array} list List of strings to match. - * @param {String|Array} patterns One or more glob patterns to use for matching. - * @param {Object} options See available [options](#options) - * @return {Array} Returns an array of matches - * @summary false - * @api public - */ + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix -const micromatch = (list, patterns, options) => { - patterns = [].concat(patterns); - list = [].concat(list); + var abs = this._makeAbs(read) - let omit = new Set(); - let keep = new Set(); - let items = new Set(); - let negatives = 0; + //if ignored, skip _processing + if (childrenIgnored(this, read)) + return cb() - let onResult = state => { - items.add(state.output); - if (options && options.onResult) { - options.onResult(state); - } - }; + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) +} - for (let i = 0; i < patterns.length; i++) { - let isMatch = picomatch(String(patterns[i]), { ...options, onResult }, true); - let negated = isMatch.state.negated || isMatch.state.negatedExtglob; - if (negated) negatives++; +Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} - for (let item of list) { - let matched = isMatch(item, true); +Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - let match = negated ? !matched.isMatch : matched.isMatch; - if (!match) continue; + // if the abs isn't a dir, then nothing can match! + if (!entries) + return cb() - if (negated) { - omit.add(matched.output); + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' + + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) } else { - omit.delete(matched.output); - keep.add(matched.output); + m = e.match(pn) } + if (m) + matchedEntries.push(e) } } - let result = negatives === patterns.length ? [...items] : [...keep]; - let matches = result.filter(item => !omit.has(item)); + //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) - if (options && matches.length === 0) { - if (options.failglob === true) { - throw new Error(`No matches found for "${patterns.join(', ')}"`); + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return cb() + + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. + + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this._emitMatch(index, e) } + // This was the last one, and no stats were needed + return cb() + } - if (options.nonull === true || options.nullglob === true) { - return options.unescape ? patterns.map(p => p.replace(/\\/g, '')) : patterns; + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e } + this._process([e].concat(remain), index, inGlobStar, cb) } + cb() +} - return matches; -}; +Glob.prototype._emitMatch = function (index, e) { + if (this.aborted) + return -/** - * Backwards compatibility - */ + if (isIgnored(this, e)) + return -micromatch.match = micromatch; + if (this.paused) { + this._emitQueue.push([index, e]) + return + } -/** - * Returns a matcher function from the given glob `pattern` and `options`. - * The returned function takes a string to match as its only argument and returns - * true if the string is a match. - * - * ```js - * const mm = require('micromatch'); - * // mm.matcher(pattern[, options]); - * - * const isMatch = mm.matcher('*.!(*a)'); - * console.log(isMatch('a.a')); //=> false - * console.log(isMatch('a.b')); //=> true - * ``` - * @param {String} `pattern` Glob pattern - * @param {Object} `options` - * @return {Function} Returns a matcher function. - * @api public - */ + var abs = isAbsolute(e) ? e : this._makeAbs(e) -micromatch.matcher = (pattern, options) => picomatch(pattern, options); + if (this.mark) + e = this._mark(e) -/** - * Returns true if **any** of the given glob `patterns` match the specified `string`. - * - * ```js - * const mm = require('micromatch'); - * // mm.isMatch(string, patterns[, options]); - * - * console.log(mm.isMatch('a.a', ['b.*', '*.a'])); //=> true - * console.log(mm.isMatch('a.a', 'b.*')); //=> false - * ``` - * @param {String} str The string to test. - * @param {String|Array} patterns One or more glob patterns to use for matching. - * @param {Object} [options] See available [options](#options). - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ + if (this.absolute) + e = abs -micromatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); + if (this.matches[index][e]) + return -/** - * Backwards compatibility - */ + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return + } -micromatch.any = micromatch.isMatch; + this.matches[index][e] = true -/** - * Returns a list of strings that _**do not match any**_ of the given `patterns`. - * - * ```js - * const mm = require('micromatch'); - * // mm.not(list, patterns[, options]); - * - * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); - * //=> ['b.b', 'c.c'] - * ``` - * @param {Array} `list` Array of strings to match. - * @param {String|Array} `patterns` One or more glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of strings that **do not match** the given patterns. - * @api public - */ + var st = this.statCache[abs] + if (st) + this.emit('stat', e, st) -micromatch.not = (list, patterns, options = {}) => { - patterns = [].concat(patterns).map(String); - let result = new Set(); - let items = []; + this.emit('match', e) +} - let onResult = state => { - if (options.onResult) options.onResult(state); - items.push(state.output); - }; +Glob.prototype._readdirInGlobStar = function (abs, cb) { + if (this.aborted) + return - let matches = micromatch(list, patterns, { ...options, onResult }); + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false, cb) - for (let item of items) { - if (!matches.includes(item)) { - result.add(item); - } - } - return [...result]; -}; + var lstatkey = 'lstat\0' + abs + var self = this + var lstatcb = inflight(lstatkey, lstatcb_) -/** - * Returns true if the given `string` contains the given pattern. Similar - * to [.isMatch](#isMatch) but the pattern can match any part of the string. - * - * ```js - * var mm = require('micromatch'); - * // mm.contains(string, pattern[, options]); - * - * console.log(mm.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(mm.contains('aa/bb/cc', '*d')); - * //=> false - * ``` - * @param {String} `str` The string to match. - * @param {String|Array} `patterns` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the patter matches any part of `str`. - * @api public - */ + if (lstatcb) + fs.lstat(abs, lstatcb) -micromatch.contains = (str, pattern, options) => { - if (typeof str !== 'string') { - throw new TypeError(`Expected a string: "${util.inspect(str)}"`); - } + function lstatcb_ (er, lstat) { + if (er && er.code === 'ENOENT') + return cb() - if (Array.isArray(pattern)) { - return pattern.some(p => micromatch.contains(str, p, options)); + var isSym = lstat && lstat.isSymbolicLink() + self.symlinks[abs] = isSym + + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && lstat && !lstat.isDirectory()) { + self.cache[abs] = 'FILE' + cb() + } else + self._readdir(abs, false, cb) } +} - if (typeof pattern === 'string') { - if (isEmptyString(str) || isEmptyString(pattern)) { - return false; - } +Glob.prototype._readdir = function (abs, inGlobStar, cb) { + if (this.aborted) + return - if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) { - return true; - } + cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) + if (!cb) + return + + //console.error('RD %j %j', +inGlobStar, abs) + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs, cb) + + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return cb() + + if (Array.isArray(c)) + return cb(null, c) } - return micromatch.isMatch(str, pattern, { ...options, contains: true }); -}; + var self = this + fs.readdir(abs, readdirCb(this, abs, cb)) +} -/** - * Filter the keys of the given object with the given `glob` pattern - * and `options`. Does not attempt to match nested keys. If you need this feature, - * use [glob-object][] instead. - * - * ```js - * const mm = require('micromatch'); - * // mm.matchKeys(object, patterns[, options]); - * - * const obj = { aa: 'a', ab: 'b', ac: 'c' }; - * console.log(mm.matchKeys(obj, '*b')); - * //=> { ab: 'b' } - * ``` - * @param {Object} `object` The object with keys to filter. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Object} Returns an object with only keys that match the given patterns. - * @api public - */ - -micromatch.matchKeys = (obj, patterns, options) => { - if (!utils.isObject(obj)) { - throw new TypeError('Expected the first argument to be an object'); +function readdirCb (self, abs, cb) { + return function (er, entries) { + if (er) + self._readdirError(abs, er, cb) + else + self._readdirEntries(abs, entries, cb) } - let keys = micromatch(Object.keys(obj), patterns, options); - let res = {}; - for (let key of keys) res[key] = obj[key]; - return res; -}; - -/** - * Returns true if some of the strings in the given `list` match any of the given glob `patterns`. - * - * ```js - * const mm = require('micromatch'); - * // mm.some(list, patterns[, options]); - * - * console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // true - * console.log(mm.some(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ +} -micromatch.some = (list, patterns, options) => { - let items = [].concat(list); +Glob.prototype._readdirEntries = function (abs, entries, cb) { + if (this.aborted) + return - for (let pattern of [].concat(patterns)) { - let isMatch = picomatch(String(pattern), options); - if (items.some(item => isMatch(item))) { - return true; + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true } } - return false; -}; -/** - * Returns true if every string in the given `list` matches - * any of the given glob `patterns`. - * - * ```js - * const mm = require('micromatch'); - * // mm.every(list, patterns[, options]); - * - * console.log(mm.every('foo.js', ['foo.js'])); - * // true - * console.log(mm.every(['foo.js', 'bar.js'], ['*.js'])); - * // true - * console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // false - * console.log(mm.every(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ + this.cache[abs] = entries + return cb(null, entries) +} -micromatch.every = (list, patterns, options) => { - let items = [].concat(list); +Glob.prototype._readdirError = function (f, er, cb) { + if (this.aborted) + return - for (let pattern of [].concat(patterns)) { - let isMatch = picomatch(String(pattern), options); - if (!items.every(item => isMatch(item))) { - return false; - } - } - return true; -}; + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + var abs = this._makeAbs(f) + this.cache[abs] = 'FILE' + if (abs === this.cwdAbs) { + var error = new Error(er.code + ' invalid cwd ' + this.cwd) + error.path = this.cwd + error.code = er.code + this.emit('error', error) + this.abort() + } + break -/** - * Returns true if **all** of the given `patterns` match - * the specified string. - * - * ```js - * const mm = require('micromatch'); - * // mm.all(string, patterns[, options]); - * - * console.log(mm.all('foo.js', ['foo.js'])); - * // true - * - * console.log(mm.all('foo.js', ['*.js', '!foo.js'])); - * // false - * - * console.log(mm.all('foo.js', ['*.js', 'foo.js'])); - * // true - * - * console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); - * // true - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break -micromatch.all = (str, patterns, options) => { - if (typeof str !== 'string') { - throw new TypeError(`Expected a string: "${util.inspect(str)}"`); + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) { + this.emit('error', er) + // If the error is handled, then we abort + // if not, we threw out of here + this.abort() + } + if (!this.silent) + console.error('glob error', er) + break } - return [].concat(patterns).every(p => picomatch(p, options)(str)); -}; + return cb() +} -/** - * Returns an array of matches captured by `pattern` in `string, or `null` if the pattern did not match. - * - * ```js - * const mm = require('micromatch'); - * // mm.capture(pattern, string[, options]); - * - * console.log(mm.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(mm.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `glob` Glob pattern to use for matching. - * @param {String} `input` String to match - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns an array of captures if the input matches the glob pattern, otherwise `null`. - * @api public - */ +Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} -micromatch.capture = (glob, input, options) => { - let posix = utils.isWindows(options); - let regex = picomatch.makeRe(String(glob), { ...options, capture: true }); - let match = regex.exec(posix ? utils.toPosixSlashes(input) : input); - if (match) { - return match.slice(1).map(v => v === void 0 ? '' : v); - } -}; +Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + //console.error('pgs2', prefix, remain[0], entries) -/** - * Create a regular expression from the given glob `pattern`. - * - * ```js - * const mm = require('micromatch'); - * // mm.makeRe(pattern[, options]); - * - * console.log(mm.makeRe('*.js')); - * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ - * ``` - * @param {String} `pattern` A glob pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} Returns a regex created from the given pattern. - * @api public - */ + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return cb() -micromatch.makeRe = (...args) => picomatch.makeRe(...args); + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) -/** - * Scan a glob pattern to separate the pattern into segments. Used - * by the [split](#split) method. - * - * ```js - * const mm = require('micromatch'); - * const state = mm.scan(pattern[, options]); - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} Returns an object with - * @api public - */ + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false, cb) -micromatch.scan = (...args) => picomatch.scan(...args); + var isSym = this.symlinks[abs] + var len = entries.length -/** - * Parse a glob pattern to create the source string for a regular - * expression. - * - * ```js - * const mm = require('micromatch'); - * const state = mm(pattern[, options]); - * ``` - * @param {String} `glob` - * @param {Object} `options` - * @return {Object} Returns an object with useful properties and output to be used as regex source string. - * @api public - */ + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return cb() -micromatch.parse = (patterns, options) => { - let res = []; - for (let pattern of [].concat(patterns || [])) { - for (let str of braces(String(pattern), options)) { - res.push(picomatch.parse(str, options)); - } + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue + + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true, cb) + + var below = gspref.concat(entries[i], remain) + this._process(below, index, true, cb) } - return res; -}; -/** - * Process the given brace `pattern`. - * - * ```js - * const { braces } = require('micromatch'); - * console.log(braces('foo/{a,b,c}/bar')); - * //=> [ 'foo/(a|b|c)/bar' ] - * - * console.log(braces('foo/{a,b,c}/bar', { expand: true })); - * //=> [ 'foo/a/bar', 'foo/b/bar', 'foo/c/bar' ] - * ``` - * @param {String} `pattern` String with brace pattern to process. - * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options. - * @return {Array} - * @api public - */ + cb() +} -micromatch.braces = (pattern, options) => { - if (typeof pattern !== 'string') throw new TypeError('Expected a string'); - if ((options && options.nobrace === true) || !/\{.*\}/.test(pattern)) { - return [pattern]; +Glob.prototype._processSimple = function (prefix, index, cb) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var self = this + this._stat(prefix, function (er, exists) { + self._processSimple2(prefix, index, er, exists, cb) + }) +} +Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { + + //console.error('ps2', prefix, exists) + + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + // If it doesn't exist, then just mark the lack of results + if (!exists) + return cb() + + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } } - return braces(pattern, options); -}; -/** - * Expand braces - */ + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') -micromatch.braceExpand = (pattern, options) => { - if (typeof pattern !== 'string') throw new TypeError('Expected a string'); - return micromatch.braces(pattern, { ...options, expand: true }); -}; + // Mark this as a match + this._emitMatch(index, prefix) + cb() +} -/** - * Expose micromatch - */ +// Returns either 'DIR', 'FILE', or false +Glob.prototype._stat = function (f, cb) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' -module.exports = micromatch; + if (f.length > this.maxLength) + return cb() + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] -/***/ }), -/* 604 */ -/***/ (function(module, exports, __webpack_require__) { + if (Array.isArray(c)) + c = 'DIR' -"use strict"; + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return cb(null, c) + if (needDir && c === 'FILE') + return cb() -const stringify = __webpack_require__(605); -const compile = __webpack_require__(607); -const expand = __webpack_require__(611); -const parse = __webpack_require__(612); + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } -/** - * Expand the given pattern or create a regex-compatible string. - * - * ```js - * const braces = require('braces'); - * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)'] - * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c'] - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {String} - * @api public - */ + var exists + var stat = this.statCache[abs] + if (stat !== undefined) { + if (stat === false) + return cb(null, stat) + else { + var type = stat.isDirectory() ? 'DIR' : 'FILE' + if (needDir && type === 'FILE') + return cb() + else + return cb(null, type, stat) + } + } -const braces = (input, options = {}) => { - let output = []; + var self = this + var statcb = inflight('stat\0' + abs, lstatcb_) + if (statcb) + fs.lstat(abs, statcb) - if (Array.isArray(input)) { - for (let pattern of input) { - let result = braces.create(pattern, options); - if (Array.isArray(result)) { - output.push(...result); - } else { - output.push(result); - } + function lstatcb_ (er, lstat) { + if (lstat && lstat.isSymbolicLink()) { + // If it's a symlink, then treat it as the target, unless + // the target does not exist, then treat it as a file. + return fs.stat(abs, function (er, stat) { + if (er) + self._stat2(f, abs, null, lstat, cb) + else + self._stat2(f, abs, er, stat, cb) + }) + } else { + self._stat2(f, abs, er, lstat, cb) } - } else { - output = [].concat(braces.create(input, options)); } +} - if (options && options.expand === true && options.nodupes === true) { - output = [...new Set(output)]; +Glob.prototype._stat2 = function (f, abs, er, stat, cb) { + if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { + this.statCache[abs] = false + return cb() } - return output; -}; -/** - * Parse the given `str` with the given `options`. - * - * ```js - * // braces.parse(pattern, [, options]); - * const ast = braces.parse('a/{b,c}/d'); - * console.log(ast); - * ``` - * @param {String} pattern Brace pattern to parse - * @param {Object} options - * @return {Object} Returns an AST - * @api public - */ + var needDir = f.slice(-1) === '/' + this.statCache[abs] = stat -braces.parse = (input, options = {}) => parse(input, options); + if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) + return cb(null, false, stat) -/** - * Creates a braces string from an AST, or an AST node. - * - * ```js - * const braces = require('braces'); - * let ast = braces.parse('foo/{a,b}/bar'); - * console.log(stringify(ast.nodes[2])); //=> '{a,b}' - * ``` - * @param {String} `input` Brace pattern or AST. - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ + var c = true + if (stat) + c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c -braces.stringify = (input, options = {}) => { - if (typeof input === 'string') { - return stringify(braces.parse(input, options), options); - } - return stringify(input, options); -}; + if (needDir && c === 'FILE') + return cb() -/** - * Compiles a brace pattern into a regex-compatible, optimized string. - * This method is called by the main [braces](#braces) function by default. - * - * ```js - * const braces = require('braces'); - * console.log(braces.compile('a/{b,c}/d')); - * //=> ['a/(b|c)/d'] - * ``` - * @param {String} `input` Brace pattern or AST. - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ + return cb(null, c, stat) +} -braces.compile = (input, options = {}) => { - if (typeof input === 'string') { - input = braces.parse(input, options); - } - return compile(input, options); -}; -/** - * Expands a brace pattern into an array. This method is called by the - * main [braces](#braces) function when `options.expand` is true. Before - * using this method it's recommended that you read the [performance notes](#performance)) - * and advantages of using [.compile](#compile) instead. - * - * ```js - * const braces = require('braces'); - * console.log(braces.expand('a/{b,c}/d')); - * //=> ['a/b/d', 'a/c/d']; - * ``` - * @param {String} `pattern` Brace pattern - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ +/***/ }), +/* 593 */ +/***/ (function(module, exports, __webpack_require__) { -braces.expand = (input, options = {}) => { - if (typeof input === 'string') { - input = braces.parse(input, options); - } +try { + var util = __webpack_require__(29); + /* istanbul ignore next */ + if (typeof util.inherits !== 'function') throw ''; + module.exports = util.inherits; +} catch (e) { + /* istanbul ignore next */ + module.exports = __webpack_require__(594); +} - let result = expand(input, options); - // filter out empty strings if specified - if (options.noempty === true) { - result = result.filter(Boolean); - } +/***/ }), +/* 594 */ +/***/ (function(module, exports) { - // filter out duplicates if specified - if (options.nodupes === true) { - result = [...new Set(result)]; +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) + } + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } } +} - return result; -}; -/** - * Processes a brace pattern and returns either an expanded array - * (if `options.expand` is true), a highly optimized regex-compatible string. - * This method is called by the main [braces](#braces) function. - * - * ```js - * const braces = require('braces'); - * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}')) - * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)' - * ``` - * @param {String} `pattern` Brace pattern - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ +/***/ }), +/* 595 */ +/***/ (function(module, exports, __webpack_require__) { -braces.create = (input, options = {}) => { - if (input === '' || input.length < 3) { - return [input]; - } +module.exports = globSync +globSync.GlobSync = GlobSync - return options.expand !== true - ? braces.compile(input, options) - : braces.expand(input, options); -}; +var fs = __webpack_require__(23) +var rp = __webpack_require__(503) +var minimatch = __webpack_require__(505) +var Minimatch = minimatch.Minimatch +var Glob = __webpack_require__(592).Glob +var util = __webpack_require__(29) +var path = __webpack_require__(16) +var assert = __webpack_require__(30) +var isAbsolute = __webpack_require__(511) +var common = __webpack_require__(596) +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var childrenIgnored = common.childrenIgnored +var isIgnored = common.isIgnored -/** - * Expose "braces" - */ +function globSync (pattern, options) { + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') -module.exports = braces; + return new GlobSync(pattern, options).found +} +function GlobSync (pattern, options) { + if (!pattern) + throw new Error('must provide pattern') -/***/ }), -/* 605 */ -/***/ (function(module, exports, __webpack_require__) { + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') -"use strict"; + if (!(this instanceof GlobSync)) + return new GlobSync(pattern, options) + setopts(this, pattern, options) -const utils = __webpack_require__(606); + if (this.noprocess) + return this -module.exports = (ast, options = {}) => { - let stringify = (node, parent = {}) => { - let invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent); - let invalidNode = node.invalid === true && options.escapeInvalid === true; - let output = ''; + var n = this.minimatch.set.length + this.matches = new Array(n) + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false) + } + this._finish() +} - if (node.value) { - if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { - return '\\' + node.value; +GlobSync.prototype._finish = function () { + assert(this instanceof GlobSync) + if (this.realpath) { + var self = this + this.matches.forEach(function (matchset, index) { + var set = self.matches[index] = Object.create(null) + for (var p in matchset) { + try { + p = self._makeAbs(p) + var real = rp.realpathSync(p, self.realpathCache) + set[real] = true + } catch (er) { + if (er.syscall === 'stat') + set[self._makeAbs(p)] = true + else + throw er + } } - return node.value; - } + }) + } + common.finish(this) +} - if (node.value) { - return node.value; - } - if (node.nodes) { - for (let child of node.nodes) { - output += stringify(child); - } - } - return output; - }; +GlobSync.prototype._process = function (pattern, index, inGlobStar) { + assert(this instanceof GlobSync) - return stringify(ast); -}; + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. + // See if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index) + return + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break -/***/ }), -/* 606 */ -/***/ (function(module, exports, __webpack_require__) { + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } -"use strict"; + var remain = pattern.slice(n) + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix -exports.isInteger = num => { - if (typeof num === 'number') { - return Number.isInteger(num); - } - if (typeof num === 'string' && num.trim() !== '') { - return Number.isInteger(Number(num)); - } - return false; -}; + var abs = this._makeAbs(read) -/** - * Find a node of the given type - */ + //if ignored, skip processing + if (childrenIgnored(this, read)) + return -exports.find = (node, type) => node.nodes.find(node => node.type === type); + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar) +} -/** - * Find a node of the given type - */ -exports.exceedsLimit = (min, max, step = 1, limit) => { - if (limit === false) return false; - if (!exports.isInteger(min) || !exports.isInteger(max)) return false; - return ((Number(max) - Number(min)) / Number(step)) >= limit; -}; +GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { + var entries = this._readdir(abs, inGlobStar) -/** - * Escape the given node with '\\' before node.value - */ + // if the abs isn't a dir, then nothing can match! + if (!entries) + return -exports.escapeNode = (block, n = 0, type) => { - let node = block.nodes[n]; - if (!node) return; + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' - if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { - if (node.escaped !== true) { - node.value = '\\' + node.value; - node.escaped = true; + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) } } -}; - -/** - * Returns true if the given brace node should be enclosed in literal braces - */ -exports.encloseBrace = node => { - if (node.type !== 'brace') return false; - if ((node.commas >> 0 + node.ranges >> 0) === 0) { - node.invalid = true; - return true; - } - return false; -}; + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return -/** - * Returns true if a brace node is invalid. - */ + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. -exports.isInvalidBrace = block => { - if (block.type !== 'brace') return false; - if (block.invalid === true || block.dollar) return true; - if ((block.commas >> 0 + block.ranges >> 0) === 0) { - block.invalid = true; - return true; - } - if (block.open !== true || block.close !== true) { - block.invalid = true; - return true; - } - return false; -}; + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) -/** - * Returns true if a node is an open or close node - */ + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix.slice(-1) !== '/') + e = prefix + '/' + e + else + e = prefix + e + } -exports.isOpenOrClose = node => { - if (node.type === 'open' || node.type === 'close') { - return true; + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this._emitMatch(index, e) + } + // This was the last one, and no stats were needed + return } - return node.open === true || node.close === true; -}; -/** - * Reduce an array of text nodes. - */ + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) + newPattern = [prefix, e] + else + newPattern = [e] + this._process(newPattern.concat(remain), index, inGlobStar) + } +} -exports.reduce = nodes => nodes.reduce((acc, node) => { - if (node.type === 'text') acc.push(node.value); - if (node.type === 'range') node.type = 'text'; - return acc; -}, []); -/** - * Flatten an array - */ +GlobSync.prototype._emitMatch = function (index, e) { + if (isIgnored(this, e)) + return -exports.flatten = (...args) => { - const result = []; - const flat = arr => { - for (let i = 0; i < arr.length; i++) { - let ele = arr[i]; - Array.isArray(ele) ? flat(ele, result) : ele !== void 0 && result.push(ele); - } - return result; - }; - flat(args); - return result; -}; + var abs = this._makeAbs(e) + if (this.mark) + e = this._mark(e) -/***/ }), -/* 607 */ -/***/ (function(module, exports, __webpack_require__) { + if (this.absolute) { + e = abs + } -"use strict"; + if (this.matches[index][e]) + return + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return + } -const fill = __webpack_require__(608); -const utils = __webpack_require__(606); + this.matches[index][e] = true -const compile = (ast, options = {}) => { - let walk = (node, parent = {}) => { - let invalidBlock = utils.isInvalidBrace(parent); - let invalidNode = node.invalid === true && options.escapeInvalid === true; - let invalid = invalidBlock === true || invalidNode === true; - let prefix = options.escapeInvalid === true ? '\\' : ''; - let output = ''; + if (this.stat) + this._stat(e) +} - if (node.isOpen === true) { - return prefix + node.value; - } - if (node.isClose === true) { - return prefix + node.value; - } - if (node.type === 'open') { - return invalid ? (prefix + node.value) : '('; - } +GlobSync.prototype._readdirInGlobStar = function (abs) { + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false) - if (node.type === 'close') { - return invalid ? (prefix + node.value) : ')'; + var entries + var lstat + var stat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + if (er.code === 'ENOENT') { + // lstat failed, doesn't exist + return null } + } - if (node.type === 'comma') { - return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|'); - } + var isSym = lstat && lstat.isSymbolicLink() + this.symlinks[abs] = isSym - if (node.value) { - return node.value; - } + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && lstat && !lstat.isDirectory()) + this.cache[abs] = 'FILE' + else + entries = this._readdir(abs, false) - if (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); - let range = fill(...args, { ...options, wrap: false, toRegex: true }); + return entries +} - if (range.length !== 0) { - return args.length > 1 && range.length > 1 ? `(${range})` : range; - } - } +GlobSync.prototype._readdir = function (abs, inGlobStar) { + var entries - if (node.nodes) { - for (let child of node.nodes) { - output += walk(child, node); - } - } - return output; - }; + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs) - return walk(ast); -}; + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return null -module.exports = compile; + if (Array.isArray(c)) + return c + } + try { + return this._readdirEntries(abs, fs.readdirSync(abs)) + } catch (er) { + this._readdirError(abs, er) + return null + } +} -/***/ }), -/* 608 */ -/***/ (function(module, exports, __webpack_require__) { +GlobSync.prototype._readdirEntries = function (abs, entries) { + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } + } -"use strict"; -/*! - * fill-range - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Licensed under the MIT License. - */ + this.cache[abs] = entries + // mark and cache dir-ness + return entries +} +GlobSync.prototype._readdirError = function (f, er) { + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + var abs = this._makeAbs(f) + this.cache[abs] = 'FILE' + if (abs === this.cwdAbs) { + var error = new Error(er.code + ' invalid cwd ' + this.cwd) + error.path = this.cwd + error.code = er.code + throw error + } + break -const util = __webpack_require__(29); -const toRegexRange = __webpack_require__(609); - -const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); - -const transform = toNumber => { - return value => toNumber === true ? Number(value) : String(value); -}; - -const isValidValue = value => { - return typeof value === 'number' || (typeof value === 'string' && value !== ''); -}; - -const isNumber = num => Number.isInteger(+num); - -const zeros = input => { - let value = `${input}`; - let index = -1; - if (value[0] === '-') value = value.slice(1); - if (value === '0') return false; - while (value[++index] === '0'); - return index > 0; -}; + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break -const stringify = (start, end, options) => { - if (typeof start === 'string' || typeof end === 'string') { - return true; + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) + throw er + if (!this.silent) + console.error('glob error', er) + break } - return options.stringify === true; -}; +} -const pad = (input, maxLength, toNumber) => { - if (maxLength > 0) { - let dash = input[0] === '-' ? '-' : ''; - if (dash) input = input.slice(1); - input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0')); - } - if (toNumber === false) { - return String(input); - } - return input; -}; +GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { -const toMaxLen = (input, maxLength) => { - let negative = input[0] === '-' ? '-' : ''; - if (negative) { - input = input.slice(1); - maxLength--; - } - while (input.length < maxLength) input = '0' + input; - return negative ? ('-' + input) : input; -}; + var entries = this._readdir(abs, inGlobStar) -const toSequence = (parts, options) => { - parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); - parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return - let prefix = options.capture ? '' : '?:'; - let positives = ''; - let negatives = ''; - let result; + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) - if (parts.positives.length) { - positives = parts.positives.join('|'); - } + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false) - if (parts.negatives.length) { - negatives = `-(${prefix}${parts.negatives.join('|')})`; - } + var len = entries.length + var isSym = this.symlinks[abs] - if (positives && negatives) { - result = `${positives}|${negatives}`; - } else { - result = positives || negatives; - } + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return - if (options.wrap) { - return `(${prefix}${result})`; - } + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue - return result; -}; + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true) -const toRange = (a, b, isNumbers, options) => { - if (isNumbers) { - return toRegexRange(a, b, { wrap: false, ...options }); + var below = gspref.concat(entries[i], remain) + this._process(below, index, true) } +} - let start = String.fromCharCode(a); - if (a === b) return start; +GlobSync.prototype._processSimple = function (prefix, index) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var exists = this._stat(prefix) - let stop = String.fromCharCode(b); - return `[${start}-${stop}]`; -}; + if (!this.matches[index]) + this.matches[index] = Object.create(null) -const toRegex = (start, end, options) => { - if (Array.isArray(start)) { - let wrap = options.wrap === true; - let prefix = options.capture ? '' : '?:'; - return wrap ? `(${prefix}${start.join('|')})` : start.join('|'); + // If it doesn't exist, then just mark the lack of results + if (!exists) + return + + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } } - return toRegexRange(start, end, options); -}; -const rangeError = (...args) => { - return new RangeError('Invalid range arguments: ' + util.inspect(...args)); -}; + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') -const invalidRange = (start, end, options) => { - if (options.strictRanges === true) throw rangeError([start, end]); - return []; -}; + // Mark this as a match + this._emitMatch(index, prefix) +} -const invalidStep = (step, options) => { - if (options.strictRanges === true) { - throw new TypeError(`Expected step "${step}" to be a number`); - } - return []; -}; +// Returns either 'DIR', 'FILE', or false +GlobSync.prototype._stat = function (f) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' -const fillNumbers = (start, end, step = 1, options = {}) => { - let a = Number(start); - let b = Number(end); + if (f.length > this.maxLength) + return false - if (!Number.isInteger(a) || !Number.isInteger(b)) { - if (options.strictRanges === true) throw rangeError([start, end]); - return []; - } + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] - // fix negative zero - if (a === 0) a = 0; - if (b === 0) b = 0; + if (Array.isArray(c)) + c = 'DIR' - let descending = a > b; - let startString = String(start); - let endString = String(end); - let stepString = String(step); - step = Math.max(Math.abs(step), 1); + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return c - let padded = zeros(startString) || zeros(endString) || zeros(stepString); - let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0; - let toNumber = padded === false && stringify(start, end, options) === false; - let format = options.transform || transform(toNumber); + if (needDir && c === 'FILE') + return false - if (options.toRegex && step === 1) { - return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options); + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. } - let parts = { negatives: [], positives: [] }; - let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); - let range = []; - let index = 0; + var exists + var stat = this.statCache[abs] + if (!stat) { + var lstat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { + this.statCache[abs] = false + return false + } + } - while (descending ? a >= b : a <= b) { - if (options.toRegex === true && step > 1) { - push(a); + if (lstat && lstat.isSymbolicLink()) { + try { + stat = fs.statSync(abs) + } catch (er) { + stat = lstat + } } else { - range.push(pad(format(a, index), maxLen, toNumber)); + stat = lstat } - a = descending ? a - step : a + step; - index++; } - if (options.toRegex === true) { - return step > 1 - ? toSequence(parts, options) - : toRegex(range, null, { wrap: false, ...options }); - } + this.statCache[abs] = stat - return range; -}; + var c = true + if (stat) + c = stat.isDirectory() ? 'DIR' : 'FILE' -const fillLetters = (start, end, step = 1, options = {}) => { - if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) { - return invalidRange(start, end, options); - } + this.cache[abs] = this.cache[abs] || c + if (needDir && c === 'FILE') + return false - let format = options.transform || (val => String.fromCharCode(val)); - let a = `${start}`.charCodeAt(0); - let b = `${end}`.charCodeAt(0); + return c +} - let descending = a > b; - let min = Math.min(a, b); - let max = Math.max(a, b); +GlobSync.prototype._mark = function (p) { + return common.mark(this, p) +} - if (options.toRegex && step === 1) { - return toRange(min, max, false, options); - } +GlobSync.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} - let range = []; - let index = 0; - while (descending ? a >= b : a <= b) { - range.push(format(a, index)); - a = descending ? a - step : a + step; - index++; - } +/***/ }), +/* 596 */ +/***/ (function(module, exports, __webpack_require__) { - if (options.toRegex === true) { - return toRegex(range, null, { wrap: false, options }); - } +exports.alphasort = alphasort +exports.alphasorti = alphasorti +exports.setopts = setopts +exports.ownProp = ownProp +exports.makeAbs = makeAbs +exports.finish = finish +exports.mark = mark +exports.isIgnored = isIgnored +exports.childrenIgnored = childrenIgnored - return range; -}; +function ownProp (obj, field) { + return Object.prototype.hasOwnProperty.call(obj, field) +} -const fill = (start, end, step, options = {}) => { - if (end == null && isValidValue(start)) { - return [start]; - } +var path = __webpack_require__(16) +var minimatch = __webpack_require__(505) +var isAbsolute = __webpack_require__(511) +var Minimatch = minimatch.Minimatch - if (!isValidValue(start) || !isValidValue(end)) { - return invalidRange(start, end, options); - } +function alphasorti (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()) +} - if (typeof step === 'function') { - return fill(start, end, 1, { transform: step }); - } +function alphasort (a, b) { + return a.localeCompare(b) +} - if (isObject(step)) { - return fill(start, end, 0, step); - } +function setupIgnores (self, options) { + self.ignore = options.ignore || [] - let opts = { ...options }; - if (opts.capture === true) opts.wrap = true; - step = step || opts.step || 1; + if (!Array.isArray(self.ignore)) + self.ignore = [self.ignore] - if (!isNumber(step)) { - if (step != null && !isObject(step)) return invalidStep(step, opts); - return fill(start, end, 1, step); + if (self.ignore.length) { + self.ignore = self.ignore.map(ignoreMap) } +} - if (isNumber(start) && isNumber(end)) { - return fillNumbers(start, end, step, opts); +// ignore patterns are always in dot:true mode. +function ignoreMap (pattern) { + var gmatcher = null + if (pattern.slice(-3) === '/**') { + var gpattern = pattern.replace(/(\/\*\*)+$/, '') + gmatcher = new Minimatch(gpattern, { dot: true }) } - return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); -}; - -module.exports = fill; - + return { + matcher: new Minimatch(pattern, { dot: true }), + gmatcher: gmatcher + } +} -/***/ }), -/* 609 */ -/***/ (function(module, exports, __webpack_require__) { +function setopts (self, pattern, options) { + if (!options) + options = {} -"use strict"; -/*! - * to-regex-range - * - * Copyright (c) 2015-present, Jon Schlinkert. - * Released under the MIT License. - */ + // base-matching: just use globstar for that. + if (options.matchBase && -1 === pattern.indexOf("/")) { + if (options.noglobstar) { + throw new Error("base matching requires globstar") + } + pattern = "**/" + pattern + } + self.silent = !!options.silent + self.pattern = pattern + self.strict = options.strict !== false + self.realpath = !!options.realpath + self.realpathCache = options.realpathCache || Object.create(null) + self.follow = !!options.follow + self.dot = !!options.dot + self.mark = !!options.mark + self.nodir = !!options.nodir + if (self.nodir) + self.mark = true + self.sync = !!options.sync + self.nounique = !!options.nounique + self.nonull = !!options.nonull + self.nosort = !!options.nosort + self.nocase = !!options.nocase + self.stat = !!options.stat + self.noprocess = !!options.noprocess + self.absolute = !!options.absolute + self.maxLength = options.maxLength || Infinity + self.cache = options.cache || Object.create(null) + self.statCache = options.statCache || Object.create(null) + self.symlinks = options.symlinks || Object.create(null) -const isNumber = __webpack_require__(610); + setupIgnores(self, options) -const toRegexRange = (min, max, options) => { - if (isNumber(min) === false) { - throw new TypeError('toRegexRange: expected the first argument to be a number'); + self.changedCwd = false + var cwd = process.cwd() + if (!ownProp(options, "cwd")) + self.cwd = cwd + else { + self.cwd = path.resolve(options.cwd) + self.changedCwd = self.cwd !== cwd } - if (max === void 0 || min === max) { - return String(min); - } + self.root = options.root || path.resolve(self.cwd, "/") + self.root = path.resolve(self.root) + if (process.platform === "win32") + self.root = self.root.replace(/\\/g, "/") - if (isNumber(max) === false) { - throw new TypeError('toRegexRange: expected the second argument to be a number.'); - } + // TODO: is an absolute `cwd` supposed to be resolved against `root`? + // e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test') + self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd) + if (process.platform === "win32") + self.cwdAbs = self.cwdAbs.replace(/\\/g, "/") + self.nomount = !!options.nomount - let opts = { relaxZeros: true, ...options }; - if (typeof opts.strictZeros === 'boolean') { - opts.relaxZeros = opts.strictZeros === false; - } + // disable comments and negation in Minimatch. + // Note that they are not supported in Glob itself anyway. + options.nonegate = true + options.nocomment = true - let relax = String(opts.relaxZeros); - let shorthand = String(opts.shorthand); - let capture = String(opts.capture); - let wrap = String(opts.wrap); - let cacheKey = min + ':' + max + '=' + relax + shorthand + capture + wrap; + self.minimatch = new Minimatch(pattern, options) + self.options = self.minimatch.options +} - if (toRegexRange.cache.hasOwnProperty(cacheKey)) { - return toRegexRange.cache[cacheKey].result; +function finish (self) { + var nou = self.nounique + var all = nou ? [] : Object.create(null) + + for (var i = 0, l = self.matches.length; i < l; i ++) { + var matches = self.matches[i] + if (!matches || Object.keys(matches).length === 0) { + if (self.nonull) { + // do like the shell, and spit out the literal glob + var literal = self.minimatch.globSet[i] + if (nou) + all.push(literal) + else + all[literal] = true + } + } else { + // had matches + var m = Object.keys(matches) + if (nou) + all.push.apply(all, m) + else + m.forEach(function (m) { + all[m] = true + }) + } } - let a = Math.min(min, max); - let b = Math.max(min, max); + if (!nou) + all = Object.keys(all) - if (Math.abs(a - b) === 1) { - let result = min + '|' + max; - if (opts.capture) { - return `(${result})`; + if (!self.nosort) + all = all.sort(self.nocase ? alphasorti : alphasort) + + // at *some* point we statted all of these + if (self.mark) { + for (var i = 0; i < all.length; i++) { + all[i] = self._mark(all[i]) } - if (opts.wrap === false) { - return result; + if (self.nodir) { + all = all.filter(function (e) { + var notDir = !(/\/$/.test(e)) + var c = self.cache[e] || self.cache[makeAbs(self, e)] + if (notDir && c) + notDir = c !== 'DIR' && !Array.isArray(c) + return notDir + }) } - return `(?:${result})`; } - let isPadded = hasPadding(min) || hasPadding(max); - let state = { min, max, a, b }; - let positives = []; - let negatives = []; + if (self.ignore.length) + all = all.filter(function(m) { + return !isIgnored(self, m) + }) - if (isPadded) { - state.isPadded = isPadded; - state.maxLen = String(state.max).length; - } - - if (a < 0) { - let newMin = b < 0 ? Math.abs(b) : 1; - negatives = splitToPatterns(newMin, Math.abs(a), state, opts); - a = state.a = 0; - } - - if (b >= 0) { - positives = splitToPatterns(a, b, state, opts); - } - - state.negatives = negatives; - state.positives = positives; - state.result = collatePatterns(negatives, positives, opts); - - if (opts.capture === true) { - state.result = `(${state.result})`; - } else if (opts.wrap !== false && (positives.length + negatives.length) > 1) { - state.result = `(?:${state.result})`; - } - - toRegexRange.cache[cacheKey] = state; - return state.result; -}; - -function collatePatterns(neg, pos, options) { - let onlyNegative = filterPatterns(neg, pos, '-', false, options) || []; - let onlyPositive = filterPatterns(pos, neg, '', false, options) || []; - let intersected = filterPatterns(neg, pos, '-?', true, options) || []; - let subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); - return subpatterns.join('|'); -} - -function splitToRanges(min, max) { - let nines = 1; - let zeros = 1; - - let stop = countNines(min, nines); - let stops = new Set([max]); - - while (min <= stop && stop <= max) { - stops.add(stop); - nines += 1; - stop = countNines(min, nines); - } - - stop = countZeros(max + 1, zeros) - 1; - - while (min < stop && stop <= max) { - stops.add(stop); - zeros += 1; - stop = countZeros(max + 1, zeros) - 1; - } - - stops = [...stops]; - stops.sort(compare); - return stops; -} - -/** - * Convert a range to a regex pattern - * @param {Number} `start` - * @param {Number} `stop` - * @return {String} - */ - -function rangeToPattern(start, stop, options) { - if (start === stop) { - return { pattern: start, count: [], digits: 0 }; - } - - let zipped = zip(start, stop); - let digits = zipped.length; - let pattern = ''; - let count = 0; - - for (let i = 0; i < digits; i++) { - let [startDigit, stopDigit] = zipped[i]; - - if (startDigit === stopDigit) { - pattern += startDigit; - - } else if (startDigit !== '0' || stopDigit !== '9') { - pattern += toCharacterClass(startDigit, stopDigit, options); - - } else { - count++; - } - } - - if (count) { - pattern += options.shorthand === true ? '\\d' : '[0-9]'; - } - - return { pattern, count: [count], digits }; + self.found = all } -function splitToPatterns(min, max, tok, options) { - let ranges = splitToRanges(min, max); - let tokens = []; - let start = min; - let prev; - - for (let i = 0; i < ranges.length; i++) { - let max = ranges[i]; - let obj = rangeToPattern(String(start), String(max), options); - let zeros = ''; - - if (!tok.isPadded && prev && prev.pattern === obj.pattern) { - if (prev.count.length > 1) { - prev.count.pop(); - } +function mark (self, p) { + var abs = makeAbs(self, p) + var c = self.cache[abs] + var m = p + if (c) { + var isDir = c === 'DIR' || Array.isArray(c) + var slash = p.slice(-1) === '/' - prev.count.push(obj.count[0]); - prev.string = prev.pattern + toQuantifier(prev.count); - start = max + 1; - continue; - } + if (isDir && !slash) + m += '/' + else if (!isDir && slash) + m = m.slice(0, -1) - if (tok.isPadded) { - zeros = padZeros(max, tok, options); + if (m !== p) { + var mabs = makeAbs(self, m) + self.statCache[mabs] = self.statCache[abs] + self.cache[mabs] = self.cache[abs] } - - obj.string = zeros + obj.pattern + toQuantifier(obj.count); - tokens.push(obj); - start = max + 1; - prev = obj; } - return tokens; + return m } -function filterPatterns(arr, comparison, prefix, intersection, options) { - let result = []; - - for (let ele of arr) { - let { string } = ele; - - // only push if _both_ are negative... - if (!intersection && !contains(comparison, 'string', string)) { - result.push(prefix + string); - } - - // or _both_ are positive - if (intersection && contains(comparison, 'string', string)) { - result.push(prefix + string); - } +// lotta situps... +function makeAbs (self, f) { + var abs = f + if (f.charAt(0) === '/') { + abs = path.join(self.root, f) + } else if (isAbsolute(f) || f === '') { + abs = f + } else if (self.changedCwd) { + abs = path.resolve(self.cwd, f) + } else { + abs = path.resolve(f) } - return result; -} - -/** - * Zip strings - */ - -function zip(a, b) { - let arr = []; - for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]); - return arr; -} - -function compare(a, b) { - return a > b ? 1 : b > a ? -1 : 0; -} - -function contains(arr, key, val) { - return arr.some(ele => ele[key] === val); -} -function countNines(min, len) { - return Number(String(min).slice(0, -len) + '9'.repeat(len)); -} + if (process.platform === 'win32') + abs = abs.replace(/\\/g, '/') -function countZeros(integer, zeros) { - return integer - (integer % Math.pow(10, zeros)); + return abs } -function toQuantifier(digits) { - let [start = 0, stop = ''] = digits; - if (stop || start > 1) { - return `{${start + (stop ? ',' + stop : '')}}`; - } - return ''; -} -function toCharacterClass(a, b, options) { - return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; -} +// Return true, if pattern ends with globstar '**', for the accompanying parent directory. +// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents +function isIgnored (self, path) { + if (!self.ignore.length) + return false -function hasPadding(str) { - return /^-?(0+)\d/.test(str); + return self.ignore.some(function(item) { + return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) + }) } -function padZeros(value, tok, options) { - if (!tok.isPadded) { - return value; - } - - let diff = Math.abs(tok.maxLen - String(value).length); - let relax = options.relaxZeros !== false; +function childrenIgnored (self, path) { + if (!self.ignore.length) + return false - switch (diff) { - case 0: - return ''; - case 1: - return relax ? '0?' : '0'; - case 2: - return relax ? '0{0,2}' : '00'; - default: { - return relax ? `0{0,${diff}}` : `0{${diff}}`; - } - } + return self.ignore.some(function(item) { + return !!(item.gmatcher && item.gmatcher.match(path)) + }) } -/** - * Cache - */ - -toRegexRange.cache = {}; -toRegexRange.clearCache = () => (toRegexRange.cache = {}); - -/** - * Expose `toRegexRange` - */ - -module.exports = toRegexRange; - /***/ }), -/* 610 */ +/* 597 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * is-number - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Released under the MIT License. - */ + +const taskManager = __webpack_require__(598); +const async_1 = __webpack_require__(626); +const stream_1 = __webpack_require__(659); +const sync_1 = __webpack_require__(660); +const settings_1 = __webpack_require__(662); +const utils = __webpack_require__(599); +function FastGlob(source, options) { + try { + assertPatternsInput(source); + } + catch (error) { + return Promise.reject(error); + } + const works = getWorks(source, async_1.default, options); + return Promise.all(works).then(utils.array.flatten); +} +(function (FastGlob) { + function sync(source, options) { + assertPatternsInput(source); + const works = getWorks(source, sync_1.default, options); + return utils.array.flatten(works); + } + FastGlob.sync = sync; + function stream(source, options) { + assertPatternsInput(source); + const works = getWorks(source, stream_1.default, options); + /** + * The stream returned by the provider cannot work with an asynchronous iterator. + * To support asynchronous iterators, regardless of the number of tasks, we always multiplex streams. + * This affects performance (+25%). I don't see best solution right now. + */ + return utils.stream.merge(works); + } + FastGlob.stream = stream; + function generateTasks(source, options) { + assertPatternsInput(source); + const patterns = [].concat(source); + const settings = new settings_1.default(options); + return taskManager.generate(patterns, settings); + } + FastGlob.generateTasks = generateTasks; +})(FastGlob || (FastGlob = {})); +function getWorks(source, _Provider, options) { + const patterns = [].concat(source); + const settings = new settings_1.default(options); + const tasks = taskManager.generate(patterns, settings); + const provider = new _Provider(settings); + return tasks.map(provider.read, provider); +} +function assertPatternsInput(source) { + if ([].concat(source).every(isString)) { + return; + } + throw new TypeError('Patterns must be a string or an array of strings'); +} +function isString(source) { + /* tslint:disable-next-line strict-type-predicates */ + return typeof source === 'string'; +} +module.exports = FastGlob; +/***/ }), +/* 598 */ +/***/ (function(module, exports, __webpack_require__) { -module.exports = function(num) { - if (typeof num === 'number') { - return num - num === 0; - } - if (typeof num === 'string' && num.trim() !== '') { - return Number.isFinite ? Number.isFinite(+num) : isFinite(+num); - } - return false; -}; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(599); +function generate(patterns, settings) { + const positivePatterns = getPositivePatterns(patterns); + const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); + /** + * When the `caseSensitiveMatch` option is disabled, all patterns must be marked as dynamic, because we cannot check + * filepath directly (without read directory). + */ + const staticPatterns = !settings.caseSensitiveMatch ? [] : positivePatterns.filter(utils.pattern.isStaticPattern); + const dynamicPatterns = !settings.caseSensitiveMatch ? positivePatterns : positivePatterns.filter(utils.pattern.isDynamicPattern); + const staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false); + const dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true); + return staticTasks.concat(dynamicTasks); +} +exports.generate = generate; +function convertPatternsToTasks(positive, negative, dynamic) { + const positivePatternsGroup = groupPatternsByBaseDirectory(positive); + // When we have a global group – there is no reason to divide the patterns into independent tasks. + // In this case, the global task covers the rest. + if ('.' in positivePatternsGroup) { + const task = convertPatternGroupToTask('.', positive, negative, dynamic); + return [task]; + } + return convertPatternGroupsToTasks(positivePatternsGroup, negative, dynamic); +} +exports.convertPatternsToTasks = convertPatternsToTasks; +function getPositivePatterns(patterns) { + return utils.pattern.getPositivePatterns(patterns); +} +exports.getPositivePatterns = getPositivePatterns; +function getNegativePatternsAsPositive(patterns, ignore) { + const negative = utils.pattern.getNegativePatterns(patterns).concat(ignore); + const positive = negative.map(utils.pattern.convertToPositivePattern); + return positive; +} +exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive; +function groupPatternsByBaseDirectory(patterns) { + return patterns.reduce((collection, pattern) => { + const base = utils.pattern.getBaseDirectory(pattern); + if (base in collection) { + collection[base].push(pattern); + } + else { + collection[base] = [pattern]; + } + return collection; + }, {}); +} +exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; +function convertPatternGroupsToTasks(positive, negative, dynamic) { + return Object.keys(positive).map((base) => { + return convertPatternGroupToTask(base, positive[base], negative, dynamic); + }); +} +exports.convertPatternGroupsToTasks = convertPatternGroupsToTasks; +function convertPatternGroupToTask(base, positive, negative, dynamic) { + return { + dynamic, + positive, + negative, + base, + patterns: [].concat(positive, negative.map(utils.pattern.convertToNegativePattern)) + }; +} +exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 611 */ +/* 599 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const array = __webpack_require__(600); +exports.array = array; +const errno = __webpack_require__(601); +exports.errno = errno; +const fs = __webpack_require__(602); +exports.fs = fs; +const path = __webpack_require__(603); +exports.path = path; +const pattern = __webpack_require__(604); +exports.pattern = pattern; +const stream = __webpack_require__(625); +exports.stream = stream; -const fill = __webpack_require__(608); -const stringify = __webpack_require__(605); -const utils = __webpack_require__(606); +/***/ }), +/* 600 */ +/***/ (function(module, exports, __webpack_require__) { -const append = (queue = '', stash = '', enclose = false) => { - let result = []; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function flatten(items) { + return items.reduce((collection, item) => [].concat(collection, item), []); +} +exports.flatten = flatten; - queue = [].concat(queue); - stash = [].concat(stash); - if (!stash.length) return queue; - if (!queue.length) { - return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; - } +/***/ }), +/* 601 */ +/***/ (function(module, exports, __webpack_require__) { - for (let item of queue) { - if (Array.isArray(item)) { - for (let value of item) { - result.push(append(value, stash, enclose)); - } - } else { - for (let ele of stash) { - if (enclose === true && typeof ele === 'string') ele = `{${ele}}`; - result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele)); - } - } - } - return utils.flatten(result); -}; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function isEnoentCodeError(error) { + return error.code === 'ENOENT'; +} +exports.isEnoentCodeError = isEnoentCodeError; -const expand = (ast, options = {}) => { - let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; - let walk = (node, parent = {}) => { - node.queue = []; +/***/ }), +/* 602 */ +/***/ (function(module, exports, __webpack_require__) { - let p = parent; - let q = parent.queue; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +class DirentFromStats { + constructor(name, stats) { + this.name = name; + this.isBlockDevice = stats.isBlockDevice.bind(stats); + this.isCharacterDevice = stats.isCharacterDevice.bind(stats); + this.isDirectory = stats.isDirectory.bind(stats); + this.isFIFO = stats.isFIFO.bind(stats); + this.isFile = stats.isFile.bind(stats); + this.isSocket = stats.isSocket.bind(stats); + this.isSymbolicLink = stats.isSymbolicLink.bind(stats); + } +} +function createDirentFromStats(name, stats) { + return new DirentFromStats(name, stats); +} +exports.createDirentFromStats = createDirentFromStats; - while (p.type !== 'brace' && p.type !== 'root' && p.parent) { - p = p.parent; - q = p.queue; - } - if (node.invalid || node.dollar) { - q.push(append(q.pop(), stringify(node, options))); - return; - } +/***/ }), +/* 603 */ +/***/ (function(module, exports, __webpack_require__) { - if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { - q.push(append(q.pop(), ['{}'])); - return; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(16); +/** + * Designed to work only with simple paths: `dir\\file`. + */ +function unixify(filepath) { + return filepath.replace(/\\/g, '/'); +} +exports.unixify = unixify; +function makeAbsolute(cwd, filepath) { + return path.resolve(cwd, filepath); +} +exports.makeAbsolute = makeAbsolute; - if (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); - if (utils.exceedsLimit(...args, options.step, rangeLimit)) { - throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); - } +/***/ }), +/* 604 */ +/***/ (function(module, exports, __webpack_require__) { - let range = fill(...args, options); - if (range.length === 0) { - range = stringify(node, options); - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(16); +const globParent = __webpack_require__(605); +const isGlob = __webpack_require__(606); +const micromatch = __webpack_require__(608); +const GLOBSTAR = '**'; +function isStaticPattern(pattern) { + return !isDynamicPattern(pattern); +} +exports.isStaticPattern = isStaticPattern; +function isDynamicPattern(pattern) { + return isGlob(pattern, { strict: false }); +} +exports.isDynamicPattern = isDynamicPattern; +function convertToPositivePattern(pattern) { + return isNegativePattern(pattern) ? pattern.slice(1) : pattern; +} +exports.convertToPositivePattern = convertToPositivePattern; +function convertToNegativePattern(pattern) { + return '!' + pattern; +} +exports.convertToNegativePattern = convertToNegativePattern; +function isNegativePattern(pattern) { + return pattern.startsWith('!') && pattern[1] !== '('; +} +exports.isNegativePattern = isNegativePattern; +function isPositivePattern(pattern) { + return !isNegativePattern(pattern); +} +exports.isPositivePattern = isPositivePattern; +function getNegativePatterns(patterns) { + return patterns.filter(isNegativePattern); +} +exports.getNegativePatterns = getNegativePatterns; +function getPositivePatterns(patterns) { + return patterns.filter(isPositivePattern); +} +exports.getPositivePatterns = getPositivePatterns; +function getBaseDirectory(pattern) { + return globParent(pattern); +} +exports.getBaseDirectory = getBaseDirectory; +function hasGlobStar(pattern) { + return pattern.indexOf(GLOBSTAR) !== -1; +} +exports.hasGlobStar = hasGlobStar; +function endsWithSlashGlobStar(pattern) { + return pattern.endsWith('/' + GLOBSTAR); +} +exports.endsWithSlashGlobStar = endsWithSlashGlobStar; +function isAffectDepthOfReadingPattern(pattern) { + const basename = path.basename(pattern); + return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); +} +exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; +function getNaiveDepth(pattern) { + const base = getBaseDirectory(pattern); + const patternDepth = pattern.split('/').length; + const patternBaseDepth = base.split('/').length; + /** + * This is a hack for pattern that has no base directory. + * + * This is related to the `*\something\*` pattern. + */ + if (base === '.') { + return patternDepth - patternBaseDepth; + } + return patternDepth - patternBaseDepth - 1; +} +exports.getNaiveDepth = getNaiveDepth; +function getMaxNaivePatternsDepth(patterns) { + return patterns.reduce((max, pattern) => { + const depth = getNaiveDepth(pattern); + return depth > max ? depth : max; + }, 0); +} +exports.getMaxNaivePatternsDepth = getMaxNaivePatternsDepth; +function makeRe(pattern, options) { + return micromatch.makeRe(pattern, options); +} +exports.makeRe = makeRe; +function convertPatternsToRe(patterns, options) { + return patterns.map((pattern) => makeRe(pattern, options)); +} +exports.convertPatternsToRe = convertPatternsToRe; +function matchAny(entry, patternsRe) { + const filepath = entry.replace(/^\.[\\\/]/, ''); + return patternsRe.some((patternRe) => patternRe.test(filepath)); +} +exports.matchAny = matchAny; - q.push(append(q.pop(), range)); - node.nodes = []; - return; - } - let enclose = utils.encloseBrace(node); - let queue = node.queue; - let block = node; +/***/ }), +/* 605 */ +/***/ (function(module, exports, __webpack_require__) { - while (block.type !== 'brace' && block.type !== 'root' && block.parent) { - block = block.parent; - queue = block.queue; - } +"use strict"; - for (let i = 0; i < node.nodes.length; i++) { - let child = node.nodes[i]; - if (child.type === 'comma' && node.type === 'brace') { - if (i === 1) queue.push(''); - queue.push(''); - continue; - } +var isGlob = __webpack_require__(606); +var pathPosixDirname = __webpack_require__(16).posix.dirname; +var isWin32 = __webpack_require__(11).platform() === 'win32'; - if (child.type === 'close') { - q.push(append(q.pop(), queue, enclose)); - continue; - } +var slash = '/'; +var backslash = /\\/g; +var enclosure = /[\{\[].*[\/]*.*[\}\]]$/; +var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; +var escaped = /\\([\*\?\|\[\]\(\)\{\}])/g; - if (child.value && child.type !== 'open') { - queue.push(append(queue.pop(), child.value)); - continue; - } +module.exports = function globParent(str) { + // flip windows path separators + if (isWin32 && str.indexOf(slash) < 0) { + str = str.replace(backslash, slash); + } - if (child.nodes) { - walk(child, node); - } - } + // special case for strings ending in enclosure containing path separator + if (enclosure.test(str)) { + str += slash; + } - return queue; - }; + // preserves full path in case of trailing path separator + str += 'a'; - return utils.flatten(walk(ast)); -}; + // remove path parts that are globby + do { + str = pathPosixDirname(str); + } while (isGlob(str) || globby.test(str)); -module.exports = expand; + // remove escape chars and return result + return str.replace(escaped, '$1'); +}; /***/ }), -/* 612 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - - -const stringify = __webpack_require__(605); - -/** - * Constants +/*! + * is-glob + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. */ -const { - MAX_LENGTH, - CHAR_BACKSLASH, /* \ */ - CHAR_BACKTICK, /* ` */ - CHAR_COMMA, /* , */ - CHAR_DOT, /* . */ - CHAR_LEFT_PARENTHESES, /* ( */ - CHAR_RIGHT_PARENTHESES, /* ) */ - CHAR_LEFT_CURLY_BRACE, /* { */ - CHAR_RIGHT_CURLY_BRACE, /* } */ - CHAR_LEFT_SQUARE_BRACKET, /* [ */ - CHAR_RIGHT_SQUARE_BRACKET, /* ] */ - CHAR_DOUBLE_QUOTE, /* " */ - CHAR_SINGLE_QUOTE, /* ' */ - CHAR_NO_BREAK_SPACE, - CHAR_ZERO_WIDTH_NOBREAK_SPACE -} = __webpack_require__(613); - -/** - * parse - */ +var isExtglob = __webpack_require__(607); +var chars = { '{': '}', '(': ')', '[': ']'}; +var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; +var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; -const parse = (input, options = {}) => { - if (typeof input !== 'string') { - throw new TypeError('Expected a string'); +module.exports = function isGlob(str, options) { + if (typeof str !== 'string' || str === '') { + return false; } - let opts = options || {}; - let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; - if (input.length > max) { - throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`); + if (isExtglob(str)) { + return true; } - let ast = { type: 'root', input, nodes: [] }; - let stack = [ast]; - let block = ast; - let prev = ast; - let brackets = 0; - let length = input.length; - let index = 0; - let depth = 0; - let value; - let memo = {}; + var regex = strictRegex; + var match; - /** - * Helpers - */ + // optionally relax regex + if (options && options.strict === false) { + regex = relaxedRegex; + } - const advance = () => input[index++]; - const push = node => { - if (node.type === 'text' && prev.type === 'dot') { - prev.type = 'text'; - } + while ((match = regex.exec(str))) { + if (match[2]) return true; + var idx = match.index + match[0].length; - if (prev && prev.type === 'text' && node.type === 'text') { - prev.value += node.value; - return; + // if an open bracket/brace/paren is escaped, + // set the index to the next closing character + var open = match[1]; + var close = open ? chars[open] : null; + if (open && close) { + var n = str.indexOf(close, idx); + if (n !== -1) { + idx = n + 1; + } } - block.nodes.push(node); - node.parent = block; - node.prev = prev; - prev = node; - return node; - }; - - push({ type: 'bos' }); - - while (index < length) { - block = stack[stack.length - 1]; - value = advance(); - - /** - * Invalid chars - */ - - if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { - continue; - } + str = str.slice(idx); + } + return false; +}; - /** - * Escaped chars - */ - if (value === CHAR_BACKSLASH) { - push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); - continue; - } +/***/ }), +/* 607 */ +/***/ (function(module, exports) { - /** - * Right square bracket (literal): ']' - */ +/*! + * is-extglob + * + * Copyright (c) 2014-2016, Jon Schlinkert. + * Licensed under the MIT License. + */ - if (value === CHAR_RIGHT_SQUARE_BRACKET) { - push({ type: 'text', value: '\\' + value }); - continue; - } +module.exports = function isExtglob(str) { + if (typeof str !== 'string' || str === '') { + return false; + } - /** - * Left square bracket: '[' - */ + var match; + while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { + if (match[2]) return true; + str = str.slice(match.index + match[0].length); + } - if (value === CHAR_LEFT_SQUARE_BRACKET) { - brackets++; + return false; +}; - let closed = true; - let next; - while (index < length && (next = advance())) { - value += next; +/***/ }), +/* 608 */ +/***/ (function(module, exports, __webpack_require__) { - if (next === CHAR_LEFT_SQUARE_BRACKET) { - brackets++; - continue; - } +"use strict"; - if (next === CHAR_BACKSLASH) { - value += advance(); - continue; - } - if (next === CHAR_RIGHT_SQUARE_BRACKET) { - brackets--; +const util = __webpack_require__(29); +const braces = __webpack_require__(609); +const picomatch = __webpack_require__(619); +const utils = __webpack_require__(622); +const isEmptyString = val => typeof val === 'string' && (val === '' || val === './'); - if (brackets === 0) { - break; - } - } - } +/** + * Returns an array of strings that match one or more glob patterns. + * + * ```js + * const mm = require('micromatch'); + * // mm(list, patterns[, options]); + * + * console.log(mm(['a.js', 'a.txt'], ['*.js'])); + * //=> [ 'a.js' ] + * ``` + * @param {String|Array} list List of strings to match. + * @param {String|Array} patterns One or more glob patterns to use for matching. + * @param {Object} options See available [options](#options) + * @return {Array} Returns an array of matches + * @summary false + * @api public + */ - push({ type: 'text', value }); - continue; - } +const micromatch = (list, patterns, options) => { + patterns = [].concat(patterns); + list = [].concat(list); - /** - * Parentheses - */ + let omit = new Set(); + let keep = new Set(); + let items = new Set(); + let negatives = 0; - if (value === CHAR_LEFT_PARENTHESES) { - block = push({ type: 'paren', nodes: [] }); - stack.push(block); - push({ type: 'text', value }); - continue; + let onResult = state => { + items.add(state.output); + if (options && options.onResult) { + options.onResult(state); } + }; - if (value === CHAR_RIGHT_PARENTHESES) { - if (block.type !== 'paren') { - push({ type: 'text', value }); - continue; - } - block = stack.pop(); - push({ type: 'text', value }); - block = stack[stack.length - 1]; - continue; - } + for (let i = 0; i < patterns.length; i++) { + let isMatch = picomatch(String(patterns[i]), { ...options, onResult }, true); + let negated = isMatch.state.negated || isMatch.state.negatedExtglob; + if (negated) negatives++; - /** - * Quotes: '|"|` - */ + for (let item of list) { + let matched = isMatch(item, true); - if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { - let open = value; - let next; + let match = negated ? !matched.isMatch : matched.isMatch; + if (!match) continue; - if (options.keepQuotes !== true) { - value = ''; + if (negated) { + omit.add(matched.output); + } else { + omit.delete(matched.output); + keep.add(matched.output); } + } + } - while (index < length && (next = advance())) { - if (next === CHAR_BACKSLASH) { - value += next + advance(); - continue; - } - - if (next === open) { - if (options.keepQuotes === true) value += next; - break; - } + let result = negatives === patterns.length ? [...items] : [...keep]; + let matches = result.filter(item => !omit.has(item)); - value += next; - } + if (options && matches.length === 0) { + if (options.failglob === true) { + throw new Error(`No matches found for "${patterns.join(', ')}"`); + } - push({ type: 'text', value }); - continue; + if (options.nonull === true || options.nullglob === true) { + return options.unescape ? patterns.map(p => p.replace(/\\/g, '')) : patterns; } + } - /** - * Left curly brace: '{' - */ + return matches; +}; - if (value === CHAR_LEFT_CURLY_BRACE) { - depth++; +/** + * Backwards compatibility + */ - let dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; - let brace = { - type: 'brace', - open: true, - close: false, - dollar, - depth, - commas: 0, - ranges: 0, - nodes: [] - }; +micromatch.match = micromatch; - block = push(brace); - stack.push(block); - push({ type: 'open', value }); - continue; - } +/** + * Returns a matcher function from the given glob `pattern` and `options`. + * The returned function takes a string to match as its only argument and returns + * true if the string is a match. + * + * ```js + * const mm = require('micromatch'); + * // mm.matcher(pattern[, options]); + * + * const isMatch = mm.matcher('*.!(*a)'); + * console.log(isMatch('a.a')); //=> false + * console.log(isMatch('a.b')); //=> true + * ``` + * @param {String} `pattern` Glob pattern + * @param {Object} `options` + * @return {Function} Returns a matcher function. + * @api public + */ - /** - * Right curly brace: '}' - */ +micromatch.matcher = (pattern, options) => picomatch(pattern, options); - if (value === CHAR_RIGHT_CURLY_BRACE) { - if (block.type !== 'brace') { - push({ type: 'text', value }); - continue; - } +/** + * Returns true if **any** of the given glob `patterns` match the specified `string`. + * + * ```js + * const mm = require('micromatch'); + * // mm.isMatch(string, patterns[, options]); + * + * console.log(mm.isMatch('a.a', ['b.*', '*.a'])); //=> true + * console.log(mm.isMatch('a.a', 'b.*')); //=> false + * ``` + * @param {String} str The string to test. + * @param {String|Array} patterns One or more glob patterns to use for matching. + * @param {Object} [options] See available [options](#options). + * @return {Boolean} Returns true if any patterns match `str` + * @api public + */ - let type = 'close'; - block = stack.pop(); - block.close = true; +micromatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); - push({ type, value }); - depth--; +/** + * Backwards compatibility + */ - block = stack[stack.length - 1]; - continue; - } +micromatch.any = micromatch.isMatch; - /** - * Comma: ',' - */ - - if (value === CHAR_COMMA && depth > 0) { - if (block.ranges > 0) { - block.ranges = 0; - let open = block.nodes.shift(); - block.nodes = [open, { type: 'text', value: stringify(block) }]; - } - - push({ type: 'comma', value }); - block.commas++; - continue; - } - - /** - * Dot: '.' - */ - - if (value === CHAR_DOT && depth > 0 && block.commas === 0) { - let siblings = block.nodes; - - if (depth === 0 || siblings.length === 0) { - push({ type: 'text', value }); - continue; - } - - if (prev.type === 'dot') { - block.range = []; - prev.value += value; - prev.type = 'range'; - - if (block.nodes.length !== 3 && block.nodes.length !== 5) { - block.invalid = true; - block.ranges = 0; - prev.type = 'text'; - continue; - } +/** + * Returns a list of strings that _**do not match any**_ of the given `patterns`. + * + * ```js + * const mm = require('micromatch'); + * // mm.not(list, patterns[, options]); + * + * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); + * //=> ['b.b', 'c.c'] + * ``` + * @param {Array} `list` Array of strings to match. + * @param {String|Array} `patterns` One or more glob pattern to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Array} Returns an array of strings that **do not match** the given patterns. + * @api public + */ - block.ranges++; - block.args = []; - continue; - } +micromatch.not = (list, patterns, options = {}) => { + patterns = [].concat(patterns).map(String); + let result = new Set(); + let items = []; - if (prev.type === 'range') { - siblings.pop(); + let onResult = state => { + if (options.onResult) options.onResult(state); + items.push(state.output); + }; - let before = siblings[siblings.length - 1]; - before.value += prev.value + value; - prev = before; - block.ranges--; - continue; - } + let matches = micromatch(list, patterns, { ...options, onResult }); - push({ type: 'dot', value }); - continue; + for (let item of items) { + if (!matches.includes(item)) { + result.add(item); } - - /** - * Text - */ - - push({ type: 'text', value }); } - - // Mark imbalanced braces and brackets as invalid - do { - block = stack.pop(); - - if (block.type !== 'root') { - block.nodes.forEach(node => { - if (!node.nodes) { - if (node.type === 'open') node.isOpen = true; - if (node.type === 'close') node.isClose = true; - if (!node.nodes) node.type = 'text'; - node.invalid = true; - } - }); - - // get the location of the block on parent.nodes (block's siblings) - let parent = stack[stack.length - 1]; - let index = parent.nodes.indexOf(block); - // replace the (invalid) block with it's nodes - parent.nodes.splice(index, 1, ...block.nodes); - } - } while (stack.length > 0); - - push({ type: 'eos' }); - return ast; -}; - -module.exports = parse; - - -/***/ }), -/* 613 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = { - MAX_LENGTH: 1024 * 64, - - // Digits - CHAR_0: '0', /* 0 */ - CHAR_9: '9', /* 9 */ - - // Alphabet chars. - CHAR_UPPERCASE_A: 'A', /* A */ - CHAR_LOWERCASE_A: 'a', /* a */ - CHAR_UPPERCASE_Z: 'Z', /* Z */ - CHAR_LOWERCASE_Z: 'z', /* z */ - - CHAR_LEFT_PARENTHESES: '(', /* ( */ - CHAR_RIGHT_PARENTHESES: ')', /* ) */ - - CHAR_ASTERISK: '*', /* * */ - - // Non-alphabetic chars. - CHAR_AMPERSAND: '&', /* & */ - CHAR_AT: '@', /* @ */ - CHAR_BACKSLASH: '\\', /* \ */ - CHAR_BACKTICK: '`', /* ` */ - CHAR_CARRIAGE_RETURN: '\r', /* \r */ - CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */ - CHAR_COLON: ':', /* : */ - CHAR_COMMA: ',', /* , */ - CHAR_DOLLAR: '$', /* . */ - CHAR_DOT: '.', /* . */ - CHAR_DOUBLE_QUOTE: '"', /* " */ - CHAR_EQUAL: '=', /* = */ - CHAR_EXCLAMATION_MARK: '!', /* ! */ - CHAR_FORM_FEED: '\f', /* \f */ - CHAR_FORWARD_SLASH: '/', /* / */ - CHAR_HASH: '#', /* # */ - CHAR_HYPHEN_MINUS: '-', /* - */ - CHAR_LEFT_ANGLE_BRACKET: '<', /* < */ - CHAR_LEFT_CURLY_BRACE: '{', /* { */ - CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */ - CHAR_LINE_FEED: '\n', /* \n */ - CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */ - CHAR_PERCENT: '%', /* % */ - CHAR_PLUS: '+', /* + */ - CHAR_QUESTION_MARK: '?', /* ? */ - CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */ - CHAR_RIGHT_CURLY_BRACE: '}', /* } */ - CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */ - CHAR_SEMICOLON: ';', /* ; */ - CHAR_SINGLE_QUOTE: '\'', /* ' */ - CHAR_SPACE: ' ', /* */ - CHAR_TAB: '\t', /* \t */ - CHAR_UNDERSCORE: '_', /* _ */ - CHAR_VERTICAL_LINE: '|', /* | */ - CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */ + return [...result]; }; - -/***/ }), -/* 614 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = __webpack_require__(615); - - -/***/ }), -/* 615 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const path = __webpack_require__(16); -const scan = __webpack_require__(616); -const parse = __webpack_require__(619); -const utils = __webpack_require__(617); - /** - * Creates a matcher function from one or more glob patterns. The - * returned function takes a string to match as its first argument, - * and returns true if the string is a match. The returned matcher - * function also takes a boolean as the second argument that, when true, - * returns an object with additional information. + * Returns true if the given `string` contains the given pattern. Similar + * to [.isMatch](#isMatch) but the pattern can match any part of the string. * * ```js - * const picomatch = require('picomatch'); - * // picomatch(glob[, options]); + * var mm = require('micromatch'); + * // mm.contains(string, pattern[, options]); * - * const isMatch = picomatch('*.!(*a)'); - * console.log(isMatch('a.a')); //=> false - * console.log(isMatch('a.b')); //=> true + * console.log(mm.contains('aa/bb/cc', '*b')); + * //=> true + * console.log(mm.contains('aa/bb/cc', '*d')); + * //=> false * ``` - * @name picomatch - * @param {String|Array} `globs` One or more glob patterns. - * @param {Object=} `options` - * @return {Function=} Returns a matcher function. + * @param {String} `str` The string to match. + * @param {String|Array} `patterns` Glob pattern to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Boolean} Returns true if the patter matches any part of `str`. * @api public */ -const picomatch = (glob, options, returnState = false) => { - if (Array.isArray(glob)) { - let fns = glob.map(input => picomatch(input, options, returnState)); - return str => { - for (let isMatch of fns) { - let state = isMatch(str); - if (state) return state; - } - return false; - }; - } - - if (typeof glob !== 'string' || glob === '') { - throw new TypeError('Expected pattern to be a non-empty string'); +micromatch.contains = (str, pattern, options) => { + if (typeof str !== 'string') { + throw new TypeError(`Expected a string: "${util.inspect(str)}"`); } - let opts = options || {}; - let posix = utils.isWindows(options); - let regex = picomatch.makeRe(glob, options, false, true); - let state = regex.state; - delete regex.state; - - let isIgnored = () => false; - if (opts.ignore) { - let ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; - isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); + if (Array.isArray(pattern)) { + return pattern.some(p => micromatch.contains(str, p, options)); } - const matcher = (input, returnObject = false) => { - let { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix }); - let result = { glob, state, regex, posix, input, output, match, isMatch }; - - if (typeof opts.onResult === 'function') { - opts.onResult(result); + if (typeof pattern === 'string') { + if (isEmptyString(str) || isEmptyString(pattern)) { + return false; } - if (isMatch === false) { - result.isMatch = false; - return returnObject ? result : false; + if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) { + return true; } + } - if (isIgnored(input)) { - if (typeof opts.onIgnore === 'function') { - opts.onIgnore(result); - } - result.isMatch = false; - return returnObject ? result : false; - } + return micromatch.isMatch(str, pattern, { ...options, contains: true }); +}; - if (typeof opts.onMatch === 'function') { - opts.onMatch(result); - } - return returnObject ? result : true; - }; +/** + * Filter the keys of the given object with the given `glob` pattern + * and `options`. Does not attempt to match nested keys. If you need this feature, + * use [glob-object][] instead. + * + * ```js + * const mm = require('micromatch'); + * // mm.matchKeys(object, patterns[, options]); + * + * const obj = { aa: 'a', ab: 'b', ac: 'c' }; + * console.log(mm.matchKeys(obj, '*b')); + * //=> { ab: 'b' } + * ``` + * @param {Object} `object` The object with keys to filter. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Object} Returns an object with only keys that match the given patterns. + * @api public + */ - if (returnState) { - matcher.state = state; +micromatch.matchKeys = (obj, patterns, options) => { + if (!utils.isObject(obj)) { + throw new TypeError('Expected the first argument to be an object'); } - - return matcher; + let keys = micromatch(Object.keys(obj), patterns, options); + let res = {}; + for (let key of keys) res[key] = obj[key]; + return res; }; /** - * Test `input` with the given `regex`. This is used by the main - * `picomatch()` function to test the input string. + * Returns true if some of the strings in the given `list` match any of the given glob `patterns`. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.test(input, regex[, options]); + * const mm = require('micromatch'); + * // mm.some(list, patterns[, options]); * - * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/)); - * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' } + * console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); + * // true + * console.log(mm.some(['foo.js'], ['*.js', '!foo.js'])); + * // false * ``` - * @param {String} `input` String to test. - * @param {RegExp} `regex` - * @return {Object} Returns an object with matching info. + * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Boolean} Returns true if any patterns match `str` * @api public */ -picomatch.test = (input, regex, options, { glob, posix } = {}) => { - if (typeof input !== 'string') { - throw new TypeError('Expected input to be a string'); - } +micromatch.some = (list, patterns, options) => { + let items = [].concat(list); - if (input === '') { - return { isMatch: false, output: '' }; + for (let pattern of [].concat(patterns)) { + let isMatch = picomatch(String(pattern), options); + if (items.some(item => isMatch(item))) { + return true; + } } + return false; +}; - let opts = options || {}; - let format = opts.format || (posix ? utils.toPosixSlashes : null); - let match = input === glob; - let output = (match && format) ? format(input) : input; +/** + * Returns true if every string in the given `list` matches + * any of the given glob `patterns`. + * + * ```js + * const mm = require('micromatch'); + * // mm.every(list, patterns[, options]); + * + * console.log(mm.every('foo.js', ['foo.js'])); + * // true + * console.log(mm.every(['foo.js', 'bar.js'], ['*.js'])); + * // true + * console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); + * // false + * console.log(mm.every(['foo.js'], ['*.js', '!foo.js'])); + * // false + * ``` + * @param {String|Array} `list` The string or array of strings to test. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Boolean} Returns true if any patterns match `str` + * @api public + */ - if (match === false) { - output = format ? format(input) : input; - match = output === glob; - } +micromatch.every = (list, patterns, options) => { + let items = [].concat(list); - if (match === false || opts.capture === true) { - if (opts.matchBase === true || opts.basename === true) { - match = picomatch.matchBase(input, regex, options, posix); - } else { - match = regex.exec(output); + for (let pattern of [].concat(patterns)) { + let isMatch = picomatch(String(pattern), options); + if (!items.every(item => isMatch(item))) { + return false; } } - - return { isMatch: !!match, match, output }; + return true; }; /** - * Match the basename of a filepath. + * Returns true if **all** of the given `patterns` match + * the specified string. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.matchBase(input, glob[, options]); - * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true + * const mm = require('micromatch'); + * // mm.all(string, patterns[, options]); + * + * console.log(mm.all('foo.js', ['foo.js'])); + * // true + * + * console.log(mm.all('foo.js', ['*.js', '!foo.js'])); + * // false + * + * console.log(mm.all('foo.js', ['*.js', 'foo.js'])); + * // true + * + * console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); + * // true * ``` - * @param {String} `input` String to test. - * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe). - * @return {Boolean} + * @param {String|Array} `str` The string to test. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Boolean} Returns true if any patterns match `str` * @api public */ -picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => { - let regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options); - return regex.test(path.basename(input)); +micromatch.all = (str, patterns, options) => { + if (typeof str !== 'string') { + throw new TypeError(`Expected a string: "${util.inspect(str)}"`); + } + + return [].concat(patterns).every(p => picomatch(p, options)(str)); }; /** - * Returns true if **any** of the given glob `patterns` match the specified `string`. + * Returns an array of matches captured by `pattern` in `string, or `null` if the pattern did not match. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.isMatch(string, patterns[, options]); + * const mm = require('micromatch'); + * // mm.capture(pattern, string[, options]); * - * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true - * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false + * console.log(mm.capture('test/*.js', 'test/foo.js')); + * //=> ['foo'] + * console.log(mm.capture('test/*.js', 'foo/bar.css')); + * //=> null * ``` - * @param {String|Array} str The string to test. - * @param {String|Array} patterns One or more glob patterns to use for matching. - * @param {Object} [options] See available [options](#options). - * @return {Boolean} Returns true if any patterns match `str` + * @param {String} `glob` Glob pattern to use for matching. + * @param {String} `input` String to match + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Boolean} Returns an array of captures if the input matches the glob pattern, otherwise `null`. * @api public */ -picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); +micromatch.capture = (glob, input, options) => { + let posix = utils.isWindows(options); + let regex = picomatch.makeRe(String(glob), { ...options, capture: true }); + let match = regex.exec(posix ? utils.toPosixSlashes(input) : input); + + if (match) { + return match.slice(1).map(v => v === void 0 ? '' : v); + } +}; /** - * Parse a glob pattern to create the source string for a regular - * expression. + * Create a regular expression from the given glob `pattern`. * * ```js - * const picomatch = require('picomatch'); - * const result = picomatch.parse(glob[, options]); + * const mm = require('micromatch'); + * // mm.makeRe(pattern[, options]); + * + * console.log(mm.makeRe('*.js')); + * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ * ``` - * @param {String} `glob` + * @param {String} `pattern` A glob pattern to convert to regex. * @param {Object} `options` - * @return {Object} Returns an object with useful properties and output to be used as a regex source string. + * @return {RegExp} Returns a regex created from the given pattern. * @api public */ -picomatch.parse = (glob, options) => parse(glob, options); +micromatch.makeRe = (...args) => picomatch.makeRe(...args); /** - * Scan a glob pattern to separate the pattern into segments. + * Scan a glob pattern to separate the pattern into segments. Used + * by the [split](#split) method. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.scan(input[, options]); - * - * const result = picomatch.scan('!./foo/*.js'); - * console.log(result); - * // { prefix: '!./', - * // input: '!./foo/*.js', - * // base: 'foo', - * // glob: '*.js', - * // negated: true, - * // isGlob: true } + * const mm = require('micromatch'); + * const state = mm.scan(pattern[, options]); * ``` - * @param {String} `input` Glob pattern to scan. + * @param {String} `pattern` * @param {Object} `options` * @return {Object} Returns an object with * @api public */ -picomatch.scan = (input, options) => scan(input, options); +micromatch.scan = (...args) => picomatch.scan(...args); /** - * Create a regular expression from a glob pattern. + * Parse a glob pattern to create the source string for a regular + * expression. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.makeRe(input[, options]); - * - * console.log(picomatch.makeRe('*.js')); - * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ + * const mm = require('micromatch'); + * const state = mm(pattern[, options]); * ``` - * @param {String} `input` A glob pattern to convert to regex. + * @param {String} `glob` * @param {Object} `options` - * @return {RegExp} Returns a regex created from the given pattern. + * @return {Object} Returns an object with useful properties and output to be used as regex source string. * @api public */ -picomatch.makeRe = (input, options, returnOutput = false, returnState = false) => { - if (!input || typeof input !== 'string') { - throw new TypeError('Expected a non-empty string'); - } - - let opts = options || {}; - let prepend = opts.contains ? '' : '^'; - let append = opts.contains ? '' : '$'; - let state = { negated: false, fastpaths: true }; - let prefix = ''; - let output; - - if (input.startsWith('./')) { - input = input.slice(2); - prefix = state.prefix = './'; - } - - if (opts.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { - output = parse.fastpaths(input, options); - } - - if (output === void 0) { - state = picomatch.parse(input, options); - state.prefix = prefix + (state.prefix || ''); - output = state.output; - } - - if (returnOutput === true) { - return output; - } - - let source = `${prepend}(?:${output})${append}`; - if (state && state.negated === true) { - source = `^(?!${source}).*$`; - } - - let regex = picomatch.toRegex(source, options); - if (returnState === true) { - regex.state = state; +micromatch.parse = (patterns, options) => { + let res = []; + for (let pattern of [].concat(patterns || [])) { + for (let str of braces(String(pattern), options)) { + res.push(picomatch.parse(str, options)); + } } - - return regex; + return res; }; /** - * Create a regular expression from the given regex source string. + * Process the given brace `pattern`. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.toRegex(source[, options]); + * const { braces } = require('micromatch'); + * console.log(braces('foo/{a,b,c}/bar')); + * //=> [ 'foo/(a|b|c)/bar' ] * - * const { output } = picomatch.parse('*.js'); - * console.log(picomatch.toRegex(output)); - * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ + * console.log(braces('foo/{a,b,c}/bar', { expand: true })); + * //=> [ 'foo/a/bar', 'foo/b/bar', 'foo/c/bar' ] * ``` - * @param {String} `source` Regular expression source string. - * @param {Object} `options` - * @return {RegExp} + * @param {String} `pattern` String with brace pattern to process. + * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options. + * @return {Array} * @api public */ -picomatch.toRegex = (source, options) => { - try { - let opts = options || {}; - return new RegExp(source, opts.flags || (opts.nocase ? 'i' : '')); - } catch (err) { - if (options && options.debug === true) throw err; - return /$^/; +micromatch.braces = (pattern, options) => { + if (typeof pattern !== 'string') throw new TypeError('Expected a string'); + if ((options && options.nobrace === true) || !/\{.*\}/.test(pattern)) { + return [pattern]; } + return braces(pattern, options); }; /** - * Picomatch constants. - * @return {Object} + * Expand braces */ -picomatch.constants = __webpack_require__(618); +micromatch.braceExpand = (pattern, options) => { + if (typeof pattern !== 'string') throw new TypeError('Expected a string'); + return micromatch.braces(pattern, { ...options, expand: true }); +}; /** - * Expose "picomatch" + * Expose micromatch */ -module.exports = picomatch; +module.exports = micromatch; /***/ }), -/* 616 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(617); - -const { - CHAR_ASTERISK, /* * */ - CHAR_AT, /* @ */ - CHAR_BACKWARD_SLASH, /* \ */ - CHAR_COMMA, /* , */ - CHAR_DOT, /* . */ - CHAR_EXCLAMATION_MARK, /* ! */ - CHAR_FORWARD_SLASH, /* / */ - CHAR_LEFT_CURLY_BRACE, /* { */ - CHAR_LEFT_PARENTHESES, /* ( */ - CHAR_LEFT_SQUARE_BRACKET, /* [ */ - CHAR_PLUS, /* + */ - CHAR_QUESTION_MARK, /* ? */ - CHAR_RIGHT_CURLY_BRACE, /* } */ - CHAR_RIGHT_PARENTHESES, /* ) */ - CHAR_RIGHT_SQUARE_BRACKET /* ] */ -} = __webpack_require__(618); - -const isPathSeparator = code => { - return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; -}; +const stringify = __webpack_require__(610); +const compile = __webpack_require__(612); +const expand = __webpack_require__(616); +const parse = __webpack_require__(617); /** - * Quickly scans a glob pattern and returns an object with a handful of - * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists), - * `glob` (the actual pattern), and `negated` (true if the path starts with `!`). + * Expand the given pattern or create a regex-compatible string. * * ```js - * const pm = require('picomatch'); - * console.log(pm.scan('foo/bar/*.js')); - * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' } + * const braces = require('braces'); + * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)'] + * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c'] * ``` * @param {String} `str` * @param {Object} `options` - * @return {Object} Returns an object with tokens and regex source string. + * @return {String} * @api public */ -module.exports = (input, options) => { - let opts = options || {}; - let length = input.length - 1; - let index = -1; - let start = 0; - let lastIndex = 0; - let isGlob = false; - let backslashes = false; - let negated = false; - let braces = 0; - let prev; - let code; - - let braceEscaped = false; +const braces = (input, options = {}) => { + let output = []; - let eos = () => index >= length; - let advance = () => { - prev = code; - return input.charCodeAt(++index); - }; + if (Array.isArray(input)) { + for (let pattern of input) { + let result = braces.create(pattern, options); + if (Array.isArray(result)) { + output.push(...result); + } else { + output.push(result); + } + } + } else { + output = [].concat(braces.create(input, options)); + } - while (index < length) { - code = advance(); - let next; + if (options && options.expand === true && options.nodupes === true) { + output = [...new Set(output)]; + } + return output; +}; - if (code === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); +/** + * Parse the given `str` with the given `options`. + * + * ```js + * // braces.parse(pattern, [, options]); + * const ast = braces.parse('a/{b,c}/d'); + * console.log(ast); + * ``` + * @param {String} pattern Brace pattern to parse + * @param {Object} options + * @return {Object} Returns an AST + * @api public + */ - if (next === CHAR_LEFT_CURLY_BRACE) { - braceEscaped = true; - } - continue; - } +braces.parse = (input, options = {}) => parse(input, options); - if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { - braces++; +/** + * Creates a braces string from an AST, or an AST node. + * + * ```js + * const braces = require('braces'); + * let ast = braces.parse('foo/{a,b}/bar'); + * console.log(stringify(ast.nodes[2])); //=> '{a,b}' + * ``` + * @param {String} `input` Brace pattern or AST. + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ - while (!eos() && (next = advance())) { - if (next === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); - continue; - } +braces.stringify = (input, options = {}) => { + if (typeof input === 'string') { + return stringify(braces.parse(input, options), options); + } + return stringify(input, options); +}; - if (next === CHAR_LEFT_CURLY_BRACE) { - braces++; - continue; - } +/** + * Compiles a brace pattern into a regex-compatible, optimized string. + * This method is called by the main [braces](#braces) function by default. + * + * ```js + * const braces = require('braces'); + * console.log(braces.compile('a/{b,c}/d')); + * //=> ['a/(b|c)/d'] + * ``` + * @param {String} `input` Brace pattern or AST. + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ - if (!braceEscaped && next === CHAR_DOT && (next = advance()) === CHAR_DOT) { - isGlob = true; - break; - } +braces.compile = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); + } + return compile(input, options); +}; - if (!braceEscaped && next === CHAR_COMMA) { - isGlob = true; - break; - } +/** + * Expands a brace pattern into an array. This method is called by the + * main [braces](#braces) function when `options.expand` is true. Before + * using this method it's recommended that you read the [performance notes](#performance)) + * and advantages of using [.compile](#compile) instead. + * + * ```js + * const braces = require('braces'); + * console.log(braces.expand('a/{b,c}/d')); + * //=> ['a/b/d', 'a/c/d']; + * ``` + * @param {String} `pattern` Brace pattern + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ - if (next === CHAR_RIGHT_CURLY_BRACE) { - braces--; - if (braces === 0) { - braceEscaped = false; - break; - } - } - } - } +braces.expand = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); + } - if (code === CHAR_FORWARD_SLASH) { - if (prev === CHAR_DOT && index === (start + 1)) { - start += 2; - continue; - } + let result = expand(input, options); - lastIndex = index + 1; - continue; - } + // filter out empty strings if specified + if (options.noempty === true) { + result = result.filter(Boolean); + } - if (code === CHAR_ASTERISK) { - isGlob = true; - break; - } + // filter out duplicates if specified + if (options.nodupes === true) { + result = [...new Set(result)]; + } - if (code === CHAR_ASTERISK || code === CHAR_QUESTION_MARK) { - isGlob = true; - break; - } + return result; +}; - if (code === CHAR_LEFT_SQUARE_BRACKET) { - while (!eos() && (next = advance())) { - if (next === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); - continue; - } +/** + * Processes a brace pattern and returns either an expanded array + * (if `options.expand` is true), a highly optimized regex-compatible string. + * This method is called by the main [braces](#braces) function. + * + * ```js + * const braces = require('braces'); + * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}')) + * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)' + * ``` + * @param {String} `pattern` Brace pattern + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ - if (next === CHAR_RIGHT_SQUARE_BRACKET) { - isGlob = true; - break; - } - } - } +braces.create = (input, options = {}) => { + if (input === '' || input.length < 3) { + return [input]; + } - let isExtglobChar = code === CHAR_PLUS - || code === CHAR_AT - || code === CHAR_EXCLAMATION_MARK; + return options.expand !== true + ? braces.compile(input, options) + : braces.expand(input, options); +}; - if (isExtglobChar && input.charCodeAt(index + 1) === CHAR_LEFT_PARENTHESES) { - isGlob = true; - break; - } +/** + * Expose "braces" + */ - if (code === CHAR_EXCLAMATION_MARK && index === start) { - negated = true; - start++; - continue; - } +module.exports = braces; - if (code === CHAR_LEFT_PARENTHESES) { - while (!eos() && (next = advance())) { - if (next === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); - continue; - } - if (next === CHAR_RIGHT_PARENTHESES) { - isGlob = true; - break; - } - } - } +/***/ }), +/* 610 */ +/***/ (function(module, exports, __webpack_require__) { - if (isGlob) { - break; - } - } +"use strict"; - let prefix = ''; - let orig = input; - let base = input; - let glob = ''; - if (start > 0) { - prefix = input.slice(0, start); - input = input.slice(start); - lastIndex -= start; - } +const utils = __webpack_require__(611); - if (base && isGlob === true && lastIndex > 0) { - base = input.slice(0, lastIndex); - glob = input.slice(lastIndex); - } else if (isGlob === true) { - base = ''; - glob = input; - } else { - base = input; - } +module.exports = (ast, options = {}) => { + let stringify = (node, parent = {}) => { + let invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent); + let invalidNode = node.invalid === true && options.escapeInvalid === true; + let output = ''; - if (base && base !== '' && base !== '/' && base !== input) { - if (isPathSeparator(base.charCodeAt(base.length - 1))) { - base = base.slice(0, -1); + if (node.value) { + if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { + return '\\' + node.value; + } + return node.value; } - } - if (opts.unescape === true) { - if (glob) glob = utils.removeBackslashes(glob); + if (node.value) { + return node.value; + } - if (base && backslashes === true) { - base = utils.removeBackslashes(base); + if (node.nodes) { + for (let child of node.nodes) { + output += stringify(child); + } } - } + return output; + }; - return { prefix, input: orig, base, glob, negated, isGlob }; + return stringify(ast); }; + /***/ }), -/* 617 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const path = __webpack_require__(16); -const win32 = process.platform === 'win32'; -const { - REGEX_SPECIAL_CHARS, - REGEX_SPECIAL_CHARS_GLOBAL, - REGEX_REMOVE_BACKSLASH -} = __webpack_require__(618); - -exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); -exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); -exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str); -exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1'); -exports.toPosixSlashes = str => str.replace(/\\/g, '/'); - -exports.removeBackslashes = str => { - return str.replace(REGEX_REMOVE_BACKSLASH, match => { - return match === '\\' ? '' : match; - }); -} - -exports.supportsLookbehinds = () => { - let segs = process.version.slice(1).split('.'); - if (segs.length === 3 && +segs[0] >= 9 || (+segs[0] === 8 && +segs[1] >= 10)) { - return true; +exports.isInteger = num => { + if (typeof num === 'number') { + return Number.isInteger(num); + } + if (typeof num === 'string' && num.trim() !== '') { + return Number.isInteger(Number(num)); } return false; }; -exports.isWindows = options => { - if (options && typeof options.windows === 'boolean') { - return options.windows; - } - return win32 === true || path.sep === '\\'; -}; +/** + * Find a node of the given type + */ -exports.escapeLast = (input, char, lastIdx) => { - let idx = input.lastIndexOf(char, lastIdx); - if (idx === -1) return input; - if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1); - return input.slice(0, idx) + '\\' + input.slice(idx); +exports.find = (node, type) => node.nodes.find(node => node.type === type); + +/** + * Find a node of the given type + */ + +exports.exceedsLimit = (min, max, step = 1, limit) => { + if (limit === false) return false; + if (!exports.isInteger(min) || !exports.isInteger(max)) return false; + return ((Number(max) - Number(min)) / Number(step)) >= limit; }; +/** + * Escape the given node with '\\' before node.value + */ -/***/ }), -/* 618 */ -/***/ (function(module, exports, __webpack_require__) { +exports.escapeNode = (block, n = 0, type) => { + let node = block.nodes[n]; + if (!node) return; -"use strict"; + if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { + if (node.escaped !== true) { + node.value = '\\' + node.value; + node.escaped = true; + } + } +}; +/** + * Returns true if the given brace node should be enclosed in literal braces + */ -const path = __webpack_require__(16); -const WIN_SLASH = '\\\\/'; -const WIN_NO_SLASH = `[^${WIN_SLASH}]`; +exports.encloseBrace = node => { + if (node.type !== 'brace') return false; + if ((node.commas >> 0 + node.ranges >> 0) === 0) { + node.invalid = true; + return true; + } + return false; +}; /** - * Posix glob regex + * Returns true if a brace node is invalid. */ -const DOT_LITERAL = '\\.'; -const PLUS_LITERAL = '\\+'; -const QMARK_LITERAL = '\\?'; -const SLASH_LITERAL = '\\/'; -const ONE_CHAR = '(?=.)'; -const QMARK = '[^/]'; -const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`; -const START_ANCHOR = `(?:^|${SLASH_LITERAL})`; -const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`; -const NO_DOT = `(?!${DOT_LITERAL})`; -const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`; -const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`; -const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`; -const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`; -const STAR = `${QMARK}*?`; - -const POSIX_CHARS = { - DOT_LITERAL, - PLUS_LITERAL, - QMARK_LITERAL, - SLASH_LITERAL, - ONE_CHAR, - QMARK, - END_ANCHOR, - DOTS_SLASH, - NO_DOT, - NO_DOTS, - NO_DOT_SLASH, - NO_DOTS_SLASH, - QMARK_NO_DOT, - STAR, - START_ANCHOR +exports.isInvalidBrace = block => { + if (block.type !== 'brace') return false; + if (block.invalid === true || block.dollar) return true; + if ((block.commas >> 0 + block.ranges >> 0) === 0) { + block.invalid = true; + return true; + } + if (block.open !== true || block.close !== true) { + block.invalid = true; + return true; + } + return false; }; /** - * Windows glob regex + * Returns true if a node is an open or close node */ -const WINDOWS_CHARS = { - ...POSIX_CHARS, - - SLASH_LITERAL: `[${WIN_SLASH}]`, - QMARK: WIN_NO_SLASH, - STAR: `${WIN_NO_SLASH}*?`, - DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`, - NO_DOT: `(?!${DOT_LITERAL})`, - NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, - NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`, - NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, - QMARK_NO_DOT: `[^.${WIN_SLASH}]`, - START_ANCHOR: `(?:^|[${WIN_SLASH}])`, - END_ANCHOR: `(?:[${WIN_SLASH}]|$)` +exports.isOpenOrClose = node => { + if (node.type === 'open' || node.type === 'close') { + return true; + } + return node.open === true || node.close === true; }; /** - * POSIX Bracket Regex + * Reduce an array of text nodes. */ -const POSIX_REGEX_SOURCE = { - 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' +exports.reduce = nodes => nodes.reduce((acc, node) => { + if (node.type === 'text') acc.push(node.value); + if (node.type === 'range') node.type = 'text'; + return acc; +}, []); + +/** + * Flatten an array + */ + +exports.flatten = (...args) => { + const result = []; + const flat = arr => { + for (let i = 0; i < arr.length; i++) { + let ele = arr[i]; + Array.isArray(ele) ? flat(ele, result) : ele !== void 0 && result.push(ele); + } + return result; + }; + flat(args); + return result; }; -module.exports = { - MAX_LENGTH: 1024 * 64, - POSIX_REGEX_SOURCE, - // regular expressions - REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g, - REGEX_NON_SPECIAL_CHAR: /^[^@![\].,$*+?^{}()|\\/]+/, - REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/, - REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g, - REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g, - REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g, +/***/ }), +/* 612 */ +/***/ (function(module, exports, __webpack_require__) { - // Replace globs with equivalent patterns to reduce parsing time. - REPLACEMENTS: { - '***': '*', - '**/**': '**', - '**/**/**': '**' - }, +"use strict"; - // Digits - CHAR_0: 48, /* 0 */ - CHAR_9: 57, /* 9 */ - // Alphabet chars. - CHAR_UPPERCASE_A: 65, /* A */ - CHAR_LOWERCASE_A: 97, /* a */ - CHAR_UPPERCASE_Z: 90, /* Z */ - CHAR_LOWERCASE_Z: 122, /* z */ +const fill = __webpack_require__(613); +const utils = __webpack_require__(611); - CHAR_LEFT_PARENTHESES: 40, /* ( */ - CHAR_RIGHT_PARENTHESES: 41, /* ) */ +const compile = (ast, options = {}) => { + let walk = (node, parent = {}) => { + let invalidBlock = utils.isInvalidBrace(parent); + let invalidNode = node.invalid === true && options.escapeInvalid === true; + let invalid = invalidBlock === true || invalidNode === true; + let prefix = options.escapeInvalid === true ? '\\' : ''; + let output = ''; - CHAR_ASTERISK: 42, /* * */ + if (node.isOpen === true) { + return prefix + node.value; + } + if (node.isClose === true) { + return prefix + node.value; + } - // Non-alphabetic chars. - CHAR_AMPERSAND: 38, /* & */ - CHAR_AT: 64, /* @ */ - CHAR_BACKWARD_SLASH: 92, /* \ */ - CHAR_CARRIAGE_RETURN: 13, /* \r */ - CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ - CHAR_COLON: 58, /* : */ - CHAR_COMMA: 44, /* , */ - CHAR_DOT: 46, /* . */ - CHAR_DOUBLE_QUOTE: 34, /* " */ - CHAR_EQUAL: 61, /* = */ - CHAR_EXCLAMATION_MARK: 33, /* ! */ - CHAR_FORM_FEED: 12, /* \f */ - CHAR_FORWARD_SLASH: 47, /* / */ - CHAR_GRAVE_ACCENT: 96, /* ` */ - CHAR_HASH: 35, /* # */ - CHAR_HYPHEN_MINUS: 45, /* - */ - CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ - CHAR_LEFT_CURLY_BRACE: 123, /* { */ - CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ - CHAR_LINE_FEED: 10, /* \n */ - CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ - CHAR_PERCENT: 37, /* % */ - CHAR_PLUS: 43, /* + */ - CHAR_QUESTION_MARK: 63, /* ? */ - CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ - CHAR_RIGHT_CURLY_BRACE: 125, /* } */ - CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ - CHAR_SEMICOLON: 59, /* ; */ - CHAR_SINGLE_QUOTE: 39, /* ' */ - CHAR_SPACE: 32, /* */ - CHAR_TAB: 9, /* \t */ - CHAR_UNDERSCORE: 95, /* _ */ - CHAR_VERTICAL_LINE: 124, /* | */ - CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ + if (node.type === 'open') { + return invalid ? (prefix + node.value) : '('; + } - SEP: path.sep, + if (node.type === 'close') { + return invalid ? (prefix + node.value) : ')'; + } - /** - * Create EXTGLOB_CHARS - */ + if (node.type === 'comma') { + return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|'); + } - extglobChars(chars) { - return { - '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` }, - '?': { type: 'qmark', open: '(?:', close: ')?' }, - '+': { type: 'plus', open: '(?:', close: ')+' }, - '*': { type: 'star', open: '(?:', close: ')*' }, - '@': { type: 'at', open: '(?:', close: ')' } - }; - }, + if (node.value) { + return node.value; + } - /** - * Create GLOB_CHARS - */ + if (node.nodes && node.ranges > 0) { + let args = utils.reduce(node.nodes); + let range = fill(...args, { ...options, wrap: false, toRegex: true }); - globChars(win32) { - return win32 === true ? WINDOWS_CHARS : POSIX_CHARS; - } + if (range.length !== 0) { + return args.length > 1 && range.length > 1 ? `(${range})` : range; + } + } + + if (node.nodes) { + for (let child of node.nodes) { + output += walk(child, node); + } + } + return output; + }; + + return walk(ast); }; +module.exports = compile; + /***/ }), -/* 619 */ +/* 613 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - - -const utils = __webpack_require__(617); -const constants = __webpack_require__(618); - -/** - * Constants +/*! + * fill-range + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Licensed under the MIT License. */ -const { - MAX_LENGTH, - POSIX_REGEX_SOURCE, - REGEX_NON_SPECIAL_CHAR, - REGEX_SPECIAL_CHARS_BACKREF, - REPLACEMENTS -} = constants; -/** - * Helpers - */ -const expandRange = (args, options) => { - if (typeof options.expandRange === 'function') { - return options.expandRange(...args, options); - } +const util = __webpack_require__(29); +const toRegexRange = __webpack_require__(614); - args.sort(); - let value = `[${args.join('-')}]`; +const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); - try { - /* eslint-disable no-new */ - new RegExp(value); - } catch (ex) { - return args.map(v => utils.escapeRegex(v)).join('..'); - } +const transform = toNumber => { + return value => toNumber === true ? Number(value) : String(value); +}; - return value; +const isValidValue = value => { + return typeof value === 'number' || (typeof value === 'string' && value !== ''); }; -const negate = state => { - let count = 1; +const isNumber = num => Number.isInteger(+num); - while (state.peek() === '!' && (state.peek(2) !== '(' || state.peek(3) === '?')) { - state.advance(); - state.start++; - count++; +const zeros = input => { + let value = `${input}`; + let index = -1; + if (value[0] === '-') value = value.slice(1); + if (value === '0') return false; + while (value[++index] === '0'); + return index > 0; +}; + +const stringify = (start, end, options) => { + if (typeof start === 'string' || typeof end === 'string') { + return true; } + return options.stringify === true; +}; - if (count % 2 === 0) { - return false; +const pad = (input, maxLength, toNumber) => { + if (maxLength > 0) { + let dash = input[0] === '-' ? '-' : ''; + if (dash) input = input.slice(1); + input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0')); + } + if (toNumber === false) { + return String(input); } + return input; +}; - state.negated = true; - state.start++; - return true; +const toMaxLen = (input, maxLength) => { + let negative = input[0] === '-' ? '-' : ''; + if (negative) { + input = input.slice(1); + maxLength--; + } + while (input.length < maxLength) input = '0' + input; + return negative ? ('-' + input) : input; }; -/** - * Create the message for a syntax error - */ +const toSequence = (parts, options) => { + parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); + parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); -const syntaxError = (type, char) => { - return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; -}; + let prefix = options.capture ? '' : '?:'; + let positives = ''; + let negatives = ''; + let result; -/** - * Parse the given input string. - * @param {String} input - * @param {Object} options - * @return {Object} - */ + if (parts.positives.length) { + positives = parts.positives.join('|'); + } -const parse = (input, options) => { - if (typeof input !== 'string') { - throw new TypeError('Expected a string'); + if (parts.negatives.length) { + negatives = `-(${prefix}${parts.negatives.join('|')})`; } - input = REPLACEMENTS[input] || input; + if (positives && negatives) { + result = `${positives}|${negatives}`; + } else { + result = positives || negatives; + } - let opts = { ...options }; - let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; - let len = input.length; - if (len > max) { - throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); + if (options.wrap) { + return `(${prefix}${result})`; } - let bos = { type: 'bos', value: '', output: opts.prepend || '' }; - let tokens = [bos]; + return result; +}; - let capture = opts.capture ? '' : '?:'; - let win32 = utils.isWindows(options); +const toRange = (a, b, isNumbers, options) => { + if (isNumbers) { + return toRegexRange(a, b, { wrap: false, ...options }); + } - // create constants based on platform, for windows or posix - const PLATFORM_CHARS = constants.globChars(win32); - const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS); + let start = String.fromCharCode(a); + if (a === b) return start; - const { - DOT_LITERAL, - PLUS_LITERAL, - SLASH_LITERAL, - ONE_CHAR, - DOTS_SLASH, - NO_DOT, - NO_DOT_SLASH, - NO_DOTS_SLASH, - QMARK, - QMARK_NO_DOT, - STAR, - START_ANCHOR - } = PLATFORM_CHARS; + let stop = String.fromCharCode(b); + return `[${start}-${stop}]`; +}; - const globstar = (opts) => { - return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; - }; +const toRegex = (start, end, options) => { + if (Array.isArray(start)) { + let wrap = options.wrap === true; + let prefix = options.capture ? '' : '?:'; + return wrap ? `(${prefix}${start.join('|')})` : start.join('|'); + } + return toRegexRange(start, end, options); +}; - let nodot = opts.dot ? '' : NO_DOT; - let star = opts.bash === true ? globstar(opts) : STAR; - let qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT; +const rangeError = (...args) => { + return new RangeError('Invalid range arguments: ' + util.inspect(...args)); +}; - if (opts.capture) { - star = `(${star})`; - } +const invalidRange = (start, end, options) => { + if (options.strictRanges === true) throw rangeError([start, end]); + return []; +}; - // minimatch options support - if (typeof opts.noext === 'boolean') { - opts.noextglob = opts.noext; +const invalidStep = (step, options) => { + if (options.strictRanges === true) { + throw new TypeError(`Expected step "${step}" to be a number`); } + return []; +}; - let state = { - index: -1, - start: 0, - consumed: '', - output: '', - backtrack: false, - brackets: 0, - braces: 0, - parens: 0, - quotes: 0, - tokens - }; +const fillNumbers = (start, end, step = 1, options = {}) => { + let a = Number(start); + let b = Number(end); - let extglobs = []; - let stack = []; - let prev = bos; - let value; + if (!Number.isInteger(a) || !Number.isInteger(b)) { + if (options.strictRanges === true) throw rangeError([start, end]); + return []; + } - /** - * Tokenizing helpers - */ + // fix negative zero + if (a === 0) a = 0; + if (b === 0) b = 0; - const eos = () => state.index === len - 1; - const peek = state.peek = (n = 1) => input[state.index + n]; - const advance = state.advance = () => input[++state.index]; - const append = token => { - state.output += token.output != null ? token.output : token.value; - state.consumed += token.value || ''; - }; + let descending = a > b; + let startString = String(start); + let endString = String(end); + let stepString = String(step); + step = Math.max(Math.abs(step), 1); - const increment = type => { - state[type]++; - stack.push(type); - }; + let padded = zeros(startString) || zeros(endString) || zeros(stepString); + let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0; + let toNumber = padded === false && stringify(start, end, options) === false; + let format = options.transform || transform(toNumber); - const decrement = type => { - state[type]--; - stack.pop(); - }; + if (options.toRegex && step === 1) { + return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options); + } - /** - * Push tokens onto the tokens array. This helper speeds up - * tokenizing by 1) helping us avoid backtracking as much as possible, - * and 2) helping us avoid creating extra tokens when consecutive - * characters are plain text. This improves performance and simplifies - * lookbehinds. - */ + let parts = { negatives: [], positives: [] }; + let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); + let range = []; + let index = 0; - const push = tok => { - if (prev.type === 'globstar') { - let isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace'); - let isExtglob = extglobs.length && (tok.type === 'pipe' || tok.type === 'paren'); - if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) { - state.output = state.output.slice(0, -prev.output.length); - prev.type = 'star'; - prev.value = '*'; - prev.output = star; - state.output += prev.output; - } + while (descending ? a >= b : a <= b) { + if (options.toRegex === true && step > 1) { + push(a); + } else { + range.push(pad(format(a, index), maxLen, toNumber)); } + a = descending ? a - step : a + step; + index++; + } - if (extglobs.length && tok.type !== 'paren' && !EXTGLOB_CHARS[tok.value]) { - extglobs[extglobs.length - 1].inner += tok.value; - } + if (options.toRegex === true) { + return step > 1 + ? toSequence(parts, options) + : toRegex(range, null, { wrap: false, ...options }); + } - if (tok.value || tok.output) append(tok); - if (prev && prev.type === 'text' && tok.type === 'text') { - prev.value += tok.value; - return; - } - - tok.prev = prev; - tokens.push(tok); - prev = tok; - }; + return range; +}; - const extglobOpen = (type, value) => { - let token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' }; +const fillLetters = (start, end, step = 1, options = {}) => { + if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) { + return invalidRange(start, end, options); + } - token.prev = prev; - token.parens = state.parens; - token.output = state.output; - let output = (opts.capture ? '(' : '') + token.open; - push({ type, value, output: state.output ? '' : ONE_CHAR }); - push({ type: 'paren', extglob: true, value: advance(), output }); - increment('parens'); - extglobs.push(token); - }; + let format = options.transform || (val => String.fromCharCode(val)); + let a = `${start}`.charCodeAt(0); + let b = `${end}`.charCodeAt(0); - const extglobClose = token => { - let output = token.close + (opts.capture ? ')' : ''); + let descending = a > b; + let min = Math.min(a, b); + let max = Math.max(a, b); - if (token.type === 'negate') { - let extglobStar = star; + if (options.toRegex && step === 1) { + return toRange(min, max, false, options); + } - if (token.inner && token.inner.length > 1 && token.inner.includes('/')) { - extglobStar = globstar(opts); - } + let range = []; + let index = 0; - if (extglobStar !== star || eos() || /^\)+$/.test(input.slice(state.index + 1))) { - output = token.close = ')$))' + extglobStar; - } + while (descending ? a >= b : a <= b) { + range.push(format(a, index)); + a = descending ? a - step : a + step; + index++; + } - if (token.prev.type === 'bos' && eos()) { - state.negatedExtglob = true; - } - } + if (options.toRegex === true) { + return toRegex(range, null, { wrap: false, options }); + } - push({ type: 'paren', extglob: true, value, output }); - decrement('parens'); - }; + return range; +}; - if (opts.fastpaths !== false && !/(^[*!]|[/{[()\]}"])/.test(input)) { - let backslashes = false; +const fill = (start, end, step, options = {}) => { + if (end == null && isValidValue(start)) { + return [start]; + } - let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => { - if (first === '\\') { - backslashes = true; - return m; - } + if (!isValidValue(start) || !isValidValue(end)) { + return invalidRange(start, end, options); + } - if (first === '?') { - if (esc) { - return esc + first + (rest ? QMARK.repeat(rest.length) : ''); - } - if (index === 0) { - return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : ''); - } - return QMARK.repeat(chars.length); - } + if (typeof step === 'function') { + return fill(start, end, 1, { transform: step }); + } - if (first === '.') { - return DOT_LITERAL.repeat(chars.length); - } + if (isObject(step)) { + return fill(start, end, 0, step); + } - if (first === '*') { - if (esc) { - return esc + first + (rest ? star : ''); - } - return star; - } - return esc ? m : '\\' + m; - }); + let opts = { ...options }; + if (opts.capture === true) opts.wrap = true; + step = step || opts.step || 1; - if (backslashes === true) { - if (opts.unescape === true) { - output = output.replace(/\\/g, ''); - } else { - output = output.replace(/\\+/g, m => { - return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : ''); - }); - } - } + if (!isNumber(step)) { + if (step != null && !isObject(step)) return invalidStep(step, opts); + return fill(start, end, 1, step); + } - state.output = output; - return state; + if (isNumber(start) && isNumber(end)) { + return fillNumbers(start, end, step, opts); } - /** - * Tokenize input until we reach end-of-string - */ + return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); +}; - while (!eos()) { - value = advance(); +module.exports = fill; - if (value === '\u0000') { - continue; - } - /** - * Escaped characters - */ +/***/ }), +/* 614 */ +/***/ (function(module, exports, __webpack_require__) { - if (value === '\\') { - let next = peek(); +"use strict"; +/*! + * to-regex-range + * + * Copyright (c) 2015-present, Jon Schlinkert. + * Released under the MIT License. + */ - if (next === '/' && opts.bash !== true) { - continue; - } - if (next === '.' || next === ';') { - continue; - } - if (!next) { - value += '\\'; - push({ type: 'text', value }); - continue; - } +const isNumber = __webpack_require__(615); - // collapse slashes to reduce potential for exploits - let match = /^\\+/.exec(input.slice(state.index + 1)); - let slashes = 0; +const toRegexRange = (min, max, options) => { + if (isNumber(min) === false) { + throw new TypeError('toRegexRange: expected the first argument to be a number'); + } - if (match && match[0].length > 2) { - slashes = match[0].length; - state.index += slashes; - if (slashes % 2 !== 0) { - value += '\\'; - } - } + if (max === void 0 || min === max) { + return String(min); + } - if (opts.unescape === true) { - value = advance() || ''; - } else { - value += advance() || ''; - } + if (isNumber(max) === false) { + throw new TypeError('toRegexRange: expected the second argument to be a number.'); + } - if (state.brackets === 0) { - push({ type: 'text', value }); - continue; - } - } + let opts = { relaxZeros: true, ...options }; + if (typeof opts.strictZeros === 'boolean') { + opts.relaxZeros = opts.strictZeros === false; + } - /** - * If we're inside a regex character class, continue - * until we reach the closing bracket. - */ + let relax = String(opts.relaxZeros); + let shorthand = String(opts.shorthand); + let capture = String(opts.capture); + let wrap = String(opts.wrap); + let cacheKey = min + ':' + max + '=' + relax + shorthand + capture + wrap; - if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) { - if (opts.posix !== false && value === ':') { - let inner = prev.value.slice(1); - if (inner.includes('[')) { - prev.posix = true; + if (toRegexRange.cache.hasOwnProperty(cacheKey)) { + return toRegexRange.cache[cacheKey].result; + } - if (inner.includes(':')) { - let idx = prev.value.lastIndexOf('['); - let pre = prev.value.slice(0, idx); - let rest = prev.value.slice(idx + 2); - let posix = POSIX_REGEX_SOURCE[rest]; - if (posix) { - prev.value = pre + posix; - state.backtrack = true; - advance(); + let a = Math.min(min, max); + let b = Math.max(min, max); - if (!bos.output && tokens.indexOf(prev) === 1) { - bos.output = ONE_CHAR; - } - continue; - } - } - } - } + if (Math.abs(a - b) === 1) { + let result = min + '|' + max; + if (opts.capture) { + return `(${result})`; + } + if (opts.wrap === false) { + return result; + } + return `(?:${result})`; + } - if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) { - value = '\\' + value; - } + let isPadded = hasPadding(min) || hasPadding(max); + let state = { min, max, a, b }; + let positives = []; + let negatives = []; - if (value === ']' && (prev.value === '[' || prev.value === '[^')) { - value = '\\' + value; - } + if (isPadded) { + state.isPadded = isPadded; + state.maxLen = String(state.max).length; + } - if (opts.posix === true && value === '!' && prev.value === '[') { - value = '^'; - } + if (a < 0) { + let newMin = b < 0 ? Math.abs(b) : 1; + negatives = splitToPatterns(newMin, Math.abs(a), state, opts); + a = state.a = 0; + } - prev.value += value; - append({ value }); - continue; - } + if (b >= 0) { + positives = splitToPatterns(a, b, state, opts); + } - /** - * If we're inside a quoted string, continue - * until we reach the closing double quote. - */ + state.negatives = negatives; + state.positives = positives; + state.result = collatePatterns(negatives, positives, opts); - if (state.quotes === 1 && value !== '"') { - value = utils.escapeRegex(value); - prev.value += value; - append({ value }); - continue; - } + if (opts.capture === true) { + state.result = `(${state.result})`; + } else if (opts.wrap !== false && (positives.length + negatives.length) > 1) { + state.result = `(?:${state.result})`; + } - /** - * Double quotes - */ + toRegexRange.cache[cacheKey] = state; + return state.result; +}; - if (value === '"') { - state.quotes = state.quotes === 1 ? 0 : 1; - if (opts.keepQuotes === true) { - push({ type: 'text', value }); - } - continue; - } +function collatePatterns(neg, pos, options) { + let onlyNegative = filterPatterns(neg, pos, '-', false, options) || []; + let onlyPositive = filterPatterns(pos, neg, '', false, options) || []; + let intersected = filterPatterns(neg, pos, '-?', true, options) || []; + let subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); + return subpatterns.join('|'); +} - /** - * Parentheses - */ +function splitToRanges(min, max) { + let nines = 1; + let zeros = 1; - if (value === '(') { - push({ type: 'paren', value }); - increment('parens'); - continue; - } + let stop = countNines(min, nines); + let stops = new Set([max]); - if (value === ')') { - if (state.parens === 0 && opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('opening', '(')); - } + while (min <= stop && stop <= max) { + stops.add(stop); + nines += 1; + stop = countNines(min, nines); + } - let extglob = extglobs[extglobs.length - 1]; - if (extglob && state.parens === extglob.parens + 1) { - extglobClose(extglobs.pop()); - continue; - } + stop = countZeros(max + 1, zeros) - 1; - push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); - decrement('parens'); - continue; - } + while (min < stop && stop <= max) { + stops.add(stop); + zeros += 1; + stop = countZeros(max + 1, zeros) - 1; + } - /** - * Brackets - */ + stops = [...stops]; + stops.sort(compare); + return stops; +} - if (value === '[') { - if (opts.nobracket === true || !input.slice(state.index + 1).includes(']')) { - if (opts.nobracket !== true && opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('closing', ']')); - } +/** + * Convert a range to a regex pattern + * @param {Number} `start` + * @param {Number} `stop` + * @return {String} + */ - value = '\\' + value; - } else { - increment('brackets'); - } +function rangeToPattern(start, stop, options) { + if (start === stop) { + return { pattern: start, count: [], digits: 0 }; + } - push({ type: 'bracket', value }); - continue; - } + let zipped = zip(start, stop); + let digits = zipped.length; + let pattern = ''; + let count = 0; - if (value === ']') { - if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) { - push({ type: 'text', value, output: '\\' + value }); - continue; - } + for (let i = 0; i < digits; i++) { + let [startDigit, stopDigit] = zipped[i]; - if (state.brackets === 0) { - if (opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('opening', '[')); - } + if (startDigit === stopDigit) { + pattern += startDigit; - push({ type: 'text', value, output: '\\' + value }); - continue; - } + } else if (startDigit !== '0' || stopDigit !== '9') { + pattern += toCharacterClass(startDigit, stopDigit, options); - decrement('brackets'); + } else { + count++; + } + } - let prevValue = prev.value.slice(1); - if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) { - value = '/' + value; - } + if (count) { + pattern += options.shorthand === true ? '\\d' : '[0-9]'; + } - prev.value += value; - append({ value }); + return { pattern, count: [count], digits }; +} - // when literal brackets are explicitly disabled - // assume we should match with a regex character class - if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) { - continue; - } +function splitToPatterns(min, max, tok, options) { + let ranges = splitToRanges(min, max); + let tokens = []; + let start = min; + let prev; - let escaped = utils.escapeRegex(prev.value); - state.output = state.output.slice(0, -prev.value.length); + for (let i = 0; i < ranges.length; i++) { + let max = ranges[i]; + let obj = rangeToPattern(String(start), String(max), options); + let zeros = ''; - // when literal brackets are explicitly enabled - // assume we should escape the brackets to match literal characters - if (opts.literalBrackets === true) { - state.output += escaped; - prev.value = escaped; - continue; + if (!tok.isPadded && prev && prev.pattern === obj.pattern) { + if (prev.count.length > 1) { + prev.count.pop(); } - // when the user specifies nothing, try to match both - prev.value = `(${capture}${escaped}|${prev.value})`; - state.output += prev.value; + prev.count.push(obj.count[0]); + prev.string = prev.pattern + toQuantifier(prev.count); + start = max + 1; continue; } - /** - * Braces - */ - - if (value === '{' && opts.nobrace !== true) { - push({ type: 'brace', value, output: '(' }); - increment('braces'); - continue; + if (tok.isPadded) { + zeros = padZeros(max, tok, options); } - if (value === '}') { - if (opts.nobrace === true || state.braces === 0) { - push({ type: 'text', value, output: '\\' + value }); - continue; - } - - let output = ')'; + obj.string = zeros + obj.pattern + toQuantifier(obj.count); + tokens.push(obj); + start = max + 1; + prev = obj; + } - if (state.dots === true) { - let arr = tokens.slice(); - let range = []; + return tokens; +} - for (let i = arr.length - 1; i >= 0; i--) { - tokens.pop(); - if (arr[i].type === 'brace') { - break; - } - if (arr[i].type !== 'dots') { - range.unshift(arr[i].value); - } - } +function filterPatterns(arr, comparison, prefix, intersection, options) { + let result = []; - output = expandRange(range, opts); - state.backtrack = true; - } + for (let ele of arr) { + let { string } = ele; - push({ type: 'brace', value, output }); - decrement('braces'); - continue; + // only push if _both_ are negative... + if (!intersection && !contains(comparison, 'string', string)) { + result.push(prefix + string); } - /** - * Pipes - */ - - if (value === '|') { - if (extglobs.length > 0) { - extglobs[extglobs.length - 1].conditions++; - } - push({ type: 'text', value }); - continue; + // or _both_ are positive + if (intersection && contains(comparison, 'string', string)) { + result.push(prefix + string); } + } + return result; +} - /** - * Commas - */ +/** + * Zip strings + */ - if (value === ',') { - let output = value; +function zip(a, b) { + let arr = []; + for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]); + return arr; +} - if (state.braces > 0 && stack[stack.length - 1] === 'braces') { - output = '|'; - } +function compare(a, b) { + return a > b ? 1 : b > a ? -1 : 0; +} - push({ type: 'comma', value, output }); - continue; - } +function contains(arr, key, val) { + return arr.some(ele => ele[key] === val); +} - /** - * Slashes - */ +function countNines(min, len) { + return Number(String(min).slice(0, -len) + '9'.repeat(len)); +} - if (value === '/') { - // if the beginning of the glob is "./", advance the start - // to the current index, and don't add the "./" characters - // to the state. This greatly simplifies lookbehinds when - // checking for BOS characters like "!" and "." (not "./") - if (prev.type === 'dot' && state.index === 1) { - state.start = state.index + 1; - state.consumed = ''; - state.output = ''; - tokens.pop(); - prev = bos; // reset "prev" to the first token - continue; - } +function countZeros(integer, zeros) { + return integer - (integer % Math.pow(10, zeros)); +} - push({ type: 'slash', value, output: SLASH_LITERAL }); - continue; - } +function toQuantifier(digits) { + let [start = 0, stop = ''] = digits; + if (stop || start > 1) { + return `{${start + (stop ? ',' + stop : '')}}`; + } + return ''; +} - /** - * Dots - */ +function toCharacterClass(a, b, options) { + return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; +} - if (value === '.') { - if (state.braces > 0 && prev.type === 'dot') { - if (prev.value === '.') prev.output = DOT_LITERAL; - prev.type = 'dots'; - prev.output += value; - prev.value += value; - state.dots = true; - continue; - } +function hasPadding(str) { + return /^-?(0+)\d/.test(str); +} - push({ type: 'dot', value, output: DOT_LITERAL }); - continue; - } +function padZeros(value, tok, options) { + if (!tok.isPadded) { + return value; + } - /** - * Question marks - */ + let diff = Math.abs(tok.maxLen - String(value).length); + let relax = options.relaxZeros !== false; - if (value === '?') { - if (prev && prev.type === 'paren') { - let next = peek(); - let output = value; + switch (diff) { + case 0: + return ''; + case 1: + return relax ? '0?' : '0'; + case 2: + return relax ? '0{0,2}' : '00'; + default: { + return relax ? `0{0,${diff}}` : `0{${diff}}`; + } + } +} - if (next === '<' && !utils.supportsLookbehinds()) { - throw new Error('Node.js v10 or higher is required for regex lookbehinds'); - } +/** + * Cache + */ - if (prev.value === '(' && !/[!=<:]/.test(next) || (next === '<' && !/[!=]/.test(peek(2)))) { - output = '\\' + value; - } +toRegexRange.cache = {}; +toRegexRange.clearCache = () => (toRegexRange.cache = {}); - push({ type: 'text', value, output }); - continue; - } +/** + * Expose `toRegexRange` + */ - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('qmark', value); - continue; - } +module.exports = toRegexRange; - if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { - push({ type: 'qmark', value, output: QMARK_NO_DOT }); - continue; - } - push({ type: 'qmark', value, output: QMARK }); - continue; - } +/***/ }), +/* 615 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Exclamation - */ +"use strict"; +/*! + * is-number + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Released under the MIT License. + */ - if (value === '!') { - if (opts.noextglob !== true && peek() === '(') { - if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) { - extglobOpen('negate', value); - continue; - } - } - if (opts.nonegate !== true && state.index === 0) { - negate(state); - continue; - } - } - /** - * Plus - */ +module.exports = function(num) { + if (typeof num === 'number') { + return num - num === 0; + } + if (typeof num === 'string' && num.trim() !== '') { + return Number.isFinite ? Number.isFinite(+num) : isFinite(+num); + } + return false; +}; - if (value === '+') { - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('plus', value); - continue; - } - if (prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) { - let output = prev.extglob === true ? '\\' + value : value; - push({ type: 'plus', value, output }); - continue; - } +/***/ }), +/* 616 */ +/***/ (function(module, exports, __webpack_require__) { - // use regex behavior inside parens - if (state.parens > 0 && opts.regex !== false) { - push({ type: 'plus', value }); - continue; - } +"use strict"; - push({ type: 'plus', value: PLUS_LITERAL }); - continue; - } - /** - * Plain text - */ +const fill = __webpack_require__(613); +const stringify = __webpack_require__(610); +const utils = __webpack_require__(611); - if (value === '@') { - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - push({ type: 'at', value, output: '' }); - continue; - } +const append = (queue = '', stash = '', enclose = false) => { + let result = []; - push({ type: 'text', value }); - continue; - } + queue = [].concat(queue); + stash = [].concat(stash); - /** - * Plain text - */ + if (!stash.length) return queue; + if (!queue.length) { + return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; + } - if (value !== '*') { - if (value === '$' || value === '^') { - value = '\\' + value; + for (let item of queue) { + if (Array.isArray(item)) { + for (let value of item) { + result.push(append(value, stash, enclose)); } - - let match = REGEX_NON_SPECIAL_CHAR.exec(input.slice(state.index + 1)); - if (match) { - value += match[0]; - state.index += match[0].length; + } else { + for (let ele of stash) { + if (enclose === true && typeof ele === 'string') ele = `{${ele}}`; + result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele)); } - - push({ type: 'text', value }); - continue; } + } + return utils.flatten(result); +}; - /** - * Stars - */ +const expand = (ast, options = {}) => { + let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; - if (prev && (prev.type === 'globstar' || prev.star === true)) { - prev.type = 'star'; - prev.star = true; - prev.value += value; - prev.output = star; - state.backtrack = true; - state.consumed += value; - continue; + let walk = (node, parent = {}) => { + node.queue = []; + + let p = parent; + let q = parent.queue; + + while (p.type !== 'brace' && p.type !== 'root' && p.parent) { + p = p.parent; + q = p.queue; } - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('star', value); - continue; + if (node.invalid || node.dollar) { + q.push(append(q.pop(), stringify(node, options))); + return; } - if (prev.type === 'star') { - if (opts.noglobstar === true) { - state.consumed += value; - continue; - } + if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { + q.push(append(q.pop(), ['{}'])); + return; + } - let prior = prev.prev; - let before = prior.prev; - let isStart = prior.type === 'slash' || prior.type === 'bos'; - let afterStar = before && (before.type === 'star' || before.type === 'globstar'); + if (node.nodes && node.ranges > 0) { + let args = utils.reduce(node.nodes); - if (opts.bash === true && (!isStart || (!eos() && peek() !== '/'))) { - push({ type: 'star', value, output: '' }); - continue; + if (utils.exceedsLimit(...args, options.step, rangeLimit)) { + throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); } - let isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace'); - let isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren'); - if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) { - push({ type: 'star', value, output: '' }); - continue; + let range = fill(...args, options); + if (range.length === 0) { + range = stringify(node, options); } - // strip consecutive `/**/` - while (input.slice(state.index + 1, state.index + 4) === '/**') { - let after = input[state.index + 4]; - if (after && after !== '/') { - break; - } - state.consumed += '/**'; - state.index += 3; - } + q.push(append(q.pop(), range)); + node.nodes = []; + return; + } - if (prior.type === 'bos' && eos()) { - prev.type = 'globstar'; - prev.value += value; - prev.output = globstar(opts); - state.output = prev.output; - state.consumed += value; - continue; - } + let enclose = utils.encloseBrace(node); + let queue = node.queue; + let block = node; - if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) { - state.output = state.output.slice(0, -(prior.output + prev.output).length); - prior.output = '(?:' + prior.output; + while (block.type !== 'brace' && block.type !== 'root' && block.parent) { + block = block.parent; + queue = block.queue; + } - prev.type = 'globstar'; - prev.output = globstar(opts) + '|$)'; - prev.value += value; + for (let i = 0; i < node.nodes.length; i++) { + let child = node.nodes[i]; - state.output += prior.output + prev.output; - state.consumed += value; + if (child.type === 'comma' && node.type === 'brace') { + if (i === 1) queue.push(''); + queue.push(''); continue; } - let next = peek(); - if (prior.type === 'slash' && prior.prev.type !== 'bos' && next === '/') { - let end = peek(2) !== void 0 ? '|$' : ''; - - state.output = state.output.slice(0, -(prior.output + prev.output).length); - prior.output = '(?:' + prior.output; - - prev.type = 'globstar'; - prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; - prev.value += value; - - state.output += prior.output + prev.output; - state.consumed += value + advance(); - - push({ type: 'slash', value, output: '' }); + if (child.type === 'close') { + q.push(append(q.pop(), queue, enclose)); continue; } - if (prior.type === 'bos' && next === '/') { - prev.type = 'globstar'; - prev.value += value; - prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`; - state.output = prev.output; - state.consumed += value + advance(); - push({ type: 'slash', value, output: '' }); + if (child.value && child.type !== 'open') { + queue.push(append(queue.pop(), child.value)); continue; } - // remove single star from output - state.output = state.output.slice(0, -prev.output.length); + if (child.nodes) { + walk(child, node); + } + } - // reset previous token to globstar - prev.type = 'globstar'; - prev.output = globstar(opts); - prev.value += value; + return queue; + }; - // reset output with globstar - state.output += prev.output; - state.consumed += value; - continue; - } + return utils.flatten(walk(ast)); +}; - let token = { type: 'star', value, output: star }; +module.exports = expand; - if (opts.bash === true) { - token.output = '.*?'; - if (prev.type === 'bos' || prev.type === 'slash') { - token.output = nodot + token.output; - } - push(token); - continue; - } - if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) { - token.output = value; - push(token); - continue; - } +/***/ }), +/* 617 */ +/***/ (function(module, exports, __webpack_require__) { - if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') { - if (prev.type === 'dot') { - state.output += NO_DOT_SLASH; - prev.output += NO_DOT_SLASH; +"use strict"; - } else if (opts.dot === true) { - state.output += NO_DOTS_SLASH; - prev.output += NO_DOTS_SLASH; - } else { - state.output += nodot; - prev.output += nodot; - } +const stringify = __webpack_require__(610); - if (peek() !== '*') { - state.output += ONE_CHAR; - prev.output += ONE_CHAR; - } - } +/** + * Constants + */ - push(token); - } +const { + MAX_LENGTH, + CHAR_BACKSLASH, /* \ */ + CHAR_BACKTICK, /* ` */ + CHAR_COMMA, /* , */ + CHAR_DOT, /* . */ + CHAR_LEFT_PARENTHESES, /* ( */ + CHAR_RIGHT_PARENTHESES, /* ) */ + CHAR_LEFT_CURLY_BRACE, /* { */ + CHAR_RIGHT_CURLY_BRACE, /* } */ + CHAR_LEFT_SQUARE_BRACKET, /* [ */ + CHAR_RIGHT_SQUARE_BRACKET, /* ] */ + CHAR_DOUBLE_QUOTE, /* " */ + CHAR_SINGLE_QUOTE, /* ' */ + CHAR_NO_BREAK_SPACE, + CHAR_ZERO_WIDTH_NOBREAK_SPACE +} = __webpack_require__(618); - while (state.brackets > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']')); - state.output = utils.escapeLast(state.output, '['); - decrement('brackets'); - } +/** + * parse + */ - while (state.parens > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')')); - state.output = utils.escapeLast(state.output, '('); - decrement('parens'); +const parse = (input, options = {}) => { + if (typeof input !== 'string') { + throw new TypeError('Expected a string'); } - while (state.braces > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}')); - state.output = utils.escapeLast(state.output, '{'); - decrement('braces'); + let opts = options || {}; + let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; + if (input.length > max) { + throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`); } - if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) { - push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); - } + let ast = { type: 'root', input, nodes: [] }; + let stack = [ast]; + let block = ast; + let prev = ast; + let brackets = 0; + let length = input.length; + let index = 0; + let depth = 0; + let value; + let memo = {}; - // rebuild the output if we had to backtrack at any point - if (state.backtrack === true) { - state.output = ''; + /** + * Helpers + */ - for (let token of state.tokens) { - state.output += token.output != null ? token.output : token.value; + const advance = () => input[index++]; + const push = node => { + if (node.type === 'text' && prev.type === 'dot') { + prev.type = 'text'; + } - if (token.suffix) { - state.output += token.suffix; - } + if (prev && prev.type === 'text' && node.type === 'text') { + prev.value += node.value; + return; } - } - return state; -}; + block.nodes.push(node); + node.parent = block; + node.prev = prev; + prev = node; + return node; + }; -/** - * Fast paths for creating regular expressions for common glob patterns. - * This can significantly speed up processing and has very little downside - * impact when none of the fast paths match. - */ + push({ type: 'bos' }); -parse.fastpaths = (input, options) => { - let opts = { ...options }; - let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; - let len = input.length; - if (len > max) { - throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); - } + while (index < length) { + block = stack[stack.length - 1]; + value = advance(); - input = REPLACEMENTS[input] || input; - let win32 = utils.isWindows(options); + /** + * Invalid chars + */ - // create constants based on platform, for windows or posix - const { - DOT_LITERAL, - SLASH_LITERAL, - ONE_CHAR, - DOTS_SLASH, - NO_DOT, - NO_DOTS, - NO_DOTS_SLASH, - STAR, - START_ANCHOR - } = constants.globChars(win32); + if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { + continue; + } - let capture = opts.capture ? '' : '?:'; - let star = opts.bash === true ? '.*?' : STAR; - let nodot = opts.dot ? NO_DOTS : NO_DOT; - let slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT; + /** + * Escaped chars + */ - if (opts.capture) { - star = `(${star})`; - } + if (value === CHAR_BACKSLASH) { + push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); + continue; + } - const globstar = (opts) => { - return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; - }; + /** + * Right square bracket (literal): ']' + */ - const create = str => { - switch (str) { - case '*': - return `${nodot}${ONE_CHAR}${star}`; + if (value === CHAR_RIGHT_SQUARE_BRACKET) { + push({ type: 'text', value: '\\' + value }); + continue; + } - case '.*': - return `${DOT_LITERAL}${ONE_CHAR}${star}`; + /** + * Left square bracket: '[' + */ - case '*.*': - return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; + if (value === CHAR_LEFT_SQUARE_BRACKET) { + brackets++; - case '*/*': - return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`; + let closed = true; + let next; - case '**': - return nodot + globstar(opts); + while (index < length && (next = advance())) { + value += next; - case '**/*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`; + if (next === CHAR_LEFT_SQUARE_BRACKET) { + brackets++; + continue; + } - case '**/*.*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; + if (next === CHAR_BACKSLASH) { + value += advance(); + continue; + } - case '**/.*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`; + if (next === CHAR_RIGHT_SQUARE_BRACKET) { + brackets--; - default: { - let match = /^(.*?)\.(\w+)$/.exec(str); - if (!match) return; + if (brackets === 0) { + break; + } + } + } - let source = create(match[1], options); - if (!source) return; + push({ type: 'text', value }); + continue; + } - return source + DOT_LITERAL + match[2]; + /** + * Parentheses + */ + + if (value === CHAR_LEFT_PARENTHESES) { + block = push({ type: 'paren', nodes: [] }); + stack.push(block); + push({ type: 'text', value }); + continue; + } + + if (value === CHAR_RIGHT_PARENTHESES) { + if (block.type !== 'paren') { + push({ type: 'text', value }); + continue; } + block = stack.pop(); + push({ type: 'text', value }); + block = stack[stack.length - 1]; + continue; } - }; - let output = create(input); - if (output && opts.strictSlashes !== true) { - output += `${SLASH_LITERAL}?`; - } + /** + * Quotes: '|"|` + */ - return output; -}; + if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { + let open = value; + let next; -module.exports = parse; + if (options.keepQuotes !== true) { + value = ''; + } + while (index < length && (next = advance())) { + if (next === CHAR_BACKSLASH) { + value += next + advance(); + continue; + } -/***/ }), -/* 620 */ -/***/ (function(module, exports, __webpack_require__) { + if (next === open) { + if (options.keepQuotes === true) value += next; + break; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const merge2 = __webpack_require__(591); -function merge(streams) { - const mergedStream = merge2(streams); - streams.forEach((stream) => { - stream.once('error', (err) => mergedStream.emit('error', err)); - }); - return mergedStream; -} -exports.merge = merge; + value += next; + } + push({ type: 'text', value }); + continue; + } -/***/ }), -/* 621 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Left curly brace: '{' + */ -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(622); -const provider_1 = __webpack_require__(649); -class ProviderAsync extends provider_1.default { - constructor() { - super(...arguments); - this._reader = new stream_1.default(this._settings); - } - read(task) { - const root = this._getRootDirectory(task); - const options = this._getReaderOptions(task); - const entries = []; - return new Promise((resolve, reject) => { - const stream = this.api(root, task, options); - stream.once('error', reject); - stream.on('data', (entry) => entries.push(options.transform(entry))); - stream.once('end', () => resolve(entries)); - }); - } - api(root, task, options) { - if (task.dynamic) { - return this._reader.dynamic(root, options); - } - return this._reader.static(task.patterns, options); - } -} -exports.default = ProviderAsync; + if (value === CHAR_LEFT_CURLY_BRACE) { + depth++; + let dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; + let brace = { + type: 'brace', + open: true, + close: false, + dollar, + depth, + commas: 0, + ranges: 0, + nodes: [] + }; -/***/ }), -/* 622 */ -/***/ (function(module, exports, __webpack_require__) { + block = push(brace); + stack.push(block); + push({ type: 'open', value }); + continue; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(27); -const fsStat = __webpack_require__(623); -const fsWalk = __webpack_require__(628); -const reader_1 = __webpack_require__(648); -class ReaderStream extends reader_1.default { - constructor() { - super(...arguments); - this._walkStream = fsWalk.walkStream; - this._stat = fsStat.stat; - } - dynamic(root, options) { - return this._walkStream(root, options); - } - static(patterns, options) { - const filepaths = patterns.map(this._getFullEntryPath, this); - const stream = new stream_1.PassThrough({ objectMode: true }); - stream._write = (index, _enc, done) => { - return this._getEntry(filepaths[index], patterns[index], options) - .then((entry) => { - if (entry !== null && options.entryFilter(entry)) { - stream.push(entry); - } - if (index === filepaths.length - 1) { - stream.end(); - } - done(); - }) - .catch(done); - }; - for (let i = 0; i < filepaths.length; i++) { - stream.write(i); - } - return stream; - } - _getEntry(filepath, pattern, options) { - return this._getStat(filepath) - .then((stats) => this._makeEntry(stats, pattern)) - .catch((error) => { - if (options.errorFilter(error)) { - return null; - } - throw error; - }); - } - _getStat(filepath) { - return new Promise((resolve, reject) => { - this._stat(filepath, this._fsStatSettings, (error, stats) => { - error ? reject(error) : resolve(stats); - }); - }); - } -} -exports.default = ReaderStream; + /** + * Right curly brace: '}' + */ + if (value === CHAR_RIGHT_CURLY_BRACE) { + if (block.type !== 'brace') { + push({ type: 'text', value }); + continue; + } -/***/ }), -/* 623 */ -/***/ (function(module, exports, __webpack_require__) { + let type = 'close'; + block = stack.pop(); + block.close = true; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(624); -const sync = __webpack_require__(625); -const settings_1 = __webpack_require__(626); -exports.Settings = settings_1.default; -function stat(path, optionsOrSettingsOrCallback, callback) { - if (typeof optionsOrSettingsOrCallback === 'function') { - return async.read(path, getSettings(), optionsOrSettingsOrCallback); - } - async.read(path, getSettings(optionsOrSettingsOrCallback), callback); -} -exports.stat = stat; -function statSync(path, optionsOrSettings) { - const settings = getSettings(optionsOrSettings); - return sync.read(path, settings); -} -exports.statSync = statSync; -function getSettings(settingsOrOptions = {}) { - if (settingsOrOptions instanceof settings_1.default) { - return settingsOrOptions; - } - return new settings_1.default(settingsOrOptions); -} + push({ type, value }); + depth--; + block = stack[stack.length - 1]; + continue; + } -/***/ }), -/* 624 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Comma: ',' + */ -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function read(path, settings, callback) { - settings.fs.lstat(path, (lstatError, lstat) => { - if (lstatError) { - return callFailureCallback(callback, lstatError); - } - if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { - return callSuccessCallback(callback, lstat); - } - settings.fs.stat(path, (statError, stat) => { - if (statError) { - if (settings.throwErrorOnBrokenSymbolicLink) { - return callFailureCallback(callback, statError); - } - return callSuccessCallback(callback, lstat); - } - if (settings.markSymbolicLink) { - stat.isSymbolicLink = () => true; - } - callSuccessCallback(callback, stat); - }); - }); -} -exports.read = read; -function callFailureCallback(callback, error) { - callback(error); -} -function callSuccessCallback(callback, result) { - callback(null, result); -} + if (value === CHAR_COMMA && depth > 0) { + if (block.ranges > 0) { + block.ranges = 0; + let open = block.nodes.shift(); + block.nodes = [open, { type: 'text', value: stringify(block) }]; + } + push({ type: 'comma', value }); + block.commas++; + continue; + } -/***/ }), -/* 625 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Dot: '.' + */ -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function read(path, settings) { - const lstat = settings.fs.lstatSync(path); - if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { - return lstat; - } - try { - const stat = settings.fs.statSync(path); - if (settings.markSymbolicLink) { - stat.isSymbolicLink = () => true; - } - return stat; - } - catch (error) { - if (!settings.throwErrorOnBrokenSymbolicLink) { - return lstat; - } - throw error; - } -} -exports.read = read; + if (value === CHAR_DOT && depth > 0 && block.commas === 0) { + let siblings = block.nodes; + if (depth === 0 || siblings.length === 0) { + push({ type: 'text', value }); + continue; + } -/***/ }), -/* 626 */ -/***/ (function(module, exports, __webpack_require__) { + if (prev.type === 'dot') { + block.range = []; + prev.value += value; + prev.type = 'range'; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(627); -class Settings { - constructor(_options = {}) { - this._options = _options; - this.followSymbolicLink = this._getValue(this._options.followSymbolicLink, true); - this.fs = fs.createFileSystemAdapter(this._options.fs); - this.markSymbolicLink = this._getValue(this._options.markSymbolicLink, false); - this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); - } - _getValue(option, value) { - return option === undefined ? value : option; - } -} -exports.default = Settings; + if (block.nodes.length !== 3 && block.nodes.length !== 5) { + block.invalid = true; + block.ranges = 0; + prev.type = 'text'; + continue; + } + block.ranges++; + block.args = []; + continue; + } -/***/ }), -/* 627 */ -/***/ (function(module, exports, __webpack_require__) { + if (prev.type === 'range') { + siblings.pop(); -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(23); -exports.FILE_SYSTEM_ADAPTER = { - lstat: fs.lstat, - stat: fs.stat, - lstatSync: fs.lstatSync, - statSync: fs.statSync -}; -function createFileSystemAdapter(fsMethods) { - if (!fsMethods) { - return exports.FILE_SYSTEM_ADAPTER; - } - return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); -} -exports.createFileSystemAdapter = createFileSystemAdapter; + let before = siblings[siblings.length - 1]; + before.value += prev.value + value; + prev = before; + block.ranges--; + continue; + } + push({ type: 'dot', value }); + continue; + } -/***/ }), -/* 628 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Text + */ -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(629); -const stream_1 = __webpack_require__(644); -const sync_1 = __webpack_require__(645); -const settings_1 = __webpack_require__(647); -exports.Settings = settings_1.default; -function walk(dir, optionsOrSettingsOrCallback, callback) { - if (typeof optionsOrSettingsOrCallback === 'function') { - return new async_1.default(dir, getSettings()).read(optionsOrSettingsOrCallback); - } - new async_1.default(dir, getSettings(optionsOrSettingsOrCallback)).read(callback); -} -exports.walk = walk; -function walkSync(dir, optionsOrSettings) { - const settings = getSettings(optionsOrSettings); - const provider = new sync_1.default(dir, settings); - return provider.read(); -} -exports.walkSync = walkSync; -function walkStream(dir, optionsOrSettings) { - const settings = getSettings(optionsOrSettings); - const provider = new stream_1.default(dir, settings); - return provider.read(); -} -exports.walkStream = walkStream; -function getSettings(settingsOrOptions = {}) { - if (settingsOrOptions instanceof settings_1.default) { - return settingsOrOptions; - } - return new settings_1.default(settingsOrOptions); -} + push({ type: 'text', value }); + } + // Mark imbalanced braces and brackets as invalid + do { + block = stack.pop(); -/***/ }), -/* 629 */ -/***/ (function(module, exports, __webpack_require__) { + if (block.type !== 'root') { + block.nodes.forEach(node => { + if (!node.nodes) { + if (node.type === 'open') node.isOpen = true; + if (node.type === 'close') node.isClose = true; + if (!node.nodes) node.type = 'text'; + node.invalid = true; + } + }); -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(630); -class AsyncProvider { - constructor(_root, _settings) { - this._root = _root; - this._settings = _settings; - this._reader = new async_1.default(this._root, this._settings); - this._storage = new Set(); - } - read(callback) { - this._reader.onError((error) => { - callFailureCallback(callback, error); - }); - this._reader.onEntry((entry) => { - this._storage.add(entry); - }); - this._reader.onEnd(() => { - callSuccessCallback(callback, Array.from(this._storage)); - }); - this._reader.read(); - } -} -exports.default = AsyncProvider; -function callFailureCallback(callback, error) { - callback(error); -} -function callSuccessCallback(callback, entries) { - callback(null, entries); -} + // get the location of the block on parent.nodes (block's siblings) + let parent = stack[stack.length - 1]; + let index = parent.nodes.indexOf(block); + // replace the (invalid) block with it's nodes + parent.nodes.splice(index, 1, ...block.nodes); + } + } while (stack.length > 0); + + push({ type: 'eos' }); + return ast; +}; + +module.exports = parse; /***/ }), -/* 630 */ +/* 618 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const events_1 = __webpack_require__(379); -const fsScandir = __webpack_require__(631); -const fastq = __webpack_require__(640); -const common = __webpack_require__(642); -const reader_1 = __webpack_require__(643); -class AsyncReader extends reader_1.default { - constructor(_root, _settings) { - super(_root, _settings); - this._settings = _settings; - this._scandir = fsScandir.scandir; - this._emitter = new events_1.EventEmitter(); - this._queue = fastq(this._worker.bind(this), this._settings.concurrency); - this._isFatalError = false; - this._isDestroyed = false; - this._queue.drain = () => { - if (!this._isFatalError) { - this._emitter.emit('end'); - } - }; - } - read() { - this._isFatalError = false; - this._isDestroyed = false; - setImmediate(() => { - this._pushToQueue(this._root, this._settings.basePath); - }); - return this._emitter; - } - destroy() { - if (this._isDestroyed) { - throw new Error('The reader is already destroyed'); - } - this._isDestroyed = true; - this._queue.killAndDrain(); - } - onEntry(callback) { - this._emitter.on('entry', callback); - } - onError(callback) { - this._emitter.once('error', callback); - } - onEnd(callback) { - this._emitter.once('end', callback); - } - _pushToQueue(dir, base) { - const queueItem = { dir, base }; - this._queue.push(queueItem, (error) => { - if (error) { - this._handleError(error); - } - }); - } - _worker(item, done) { - this._scandir(item.dir, this._settings.fsScandirSettings, (error, entries) => { - if (error) { - return done(error, undefined); - } - for (const entry of entries) { - this._handleEntry(entry, item.base); - } - done(null, undefined); - }); - } - _handleError(error) { - if (!common.isFatalError(this._settings, error)) { - return; - } - this._isFatalError = true; - this._isDestroyed = true; - this._emitter.emit('error', error); - } - _handleEntry(entry, base) { - if (this._isDestroyed || this._isFatalError) { - return; - } - const fullpath = entry.path; - if (base !== undefined) { - entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); - } - if (common.isAppliedFilter(this._settings.entryFilter, entry)) { - this._emitEntry(entry); - } - if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { - this._pushToQueue(fullpath, entry.path); - } - } - _emitEntry(entry) { - this._emitter.emit('entry', entry); - } -} -exports.default = AsyncReader; + + +module.exports = { + MAX_LENGTH: 1024 * 64, + + // Digits + CHAR_0: '0', /* 0 */ + CHAR_9: '9', /* 9 */ + + // Alphabet chars. + CHAR_UPPERCASE_A: 'A', /* A */ + CHAR_LOWERCASE_A: 'a', /* a */ + CHAR_UPPERCASE_Z: 'Z', /* Z */ + CHAR_LOWERCASE_Z: 'z', /* z */ + + CHAR_LEFT_PARENTHESES: '(', /* ( */ + CHAR_RIGHT_PARENTHESES: ')', /* ) */ + + CHAR_ASTERISK: '*', /* * */ + + // Non-alphabetic chars. + CHAR_AMPERSAND: '&', /* & */ + CHAR_AT: '@', /* @ */ + CHAR_BACKSLASH: '\\', /* \ */ + CHAR_BACKTICK: '`', /* ` */ + CHAR_CARRIAGE_RETURN: '\r', /* \r */ + CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */ + CHAR_COLON: ':', /* : */ + CHAR_COMMA: ',', /* , */ + CHAR_DOLLAR: '$', /* . */ + CHAR_DOT: '.', /* . */ + CHAR_DOUBLE_QUOTE: '"', /* " */ + CHAR_EQUAL: '=', /* = */ + CHAR_EXCLAMATION_MARK: '!', /* ! */ + CHAR_FORM_FEED: '\f', /* \f */ + CHAR_FORWARD_SLASH: '/', /* / */ + CHAR_HASH: '#', /* # */ + CHAR_HYPHEN_MINUS: '-', /* - */ + CHAR_LEFT_ANGLE_BRACKET: '<', /* < */ + CHAR_LEFT_CURLY_BRACE: '{', /* { */ + CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */ + CHAR_LINE_FEED: '\n', /* \n */ + CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */ + CHAR_PERCENT: '%', /* % */ + CHAR_PLUS: '+', /* + */ + CHAR_QUESTION_MARK: '?', /* ? */ + CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */ + CHAR_RIGHT_CURLY_BRACE: '}', /* } */ + CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */ + CHAR_SEMICOLON: ';', /* ; */ + CHAR_SINGLE_QUOTE: '\'', /* ' */ + CHAR_SPACE: ' ', /* */ + CHAR_TAB: '\t', /* \t */ + CHAR_UNDERSCORE: '_', /* _ */ + CHAR_VERTICAL_LINE: '|', /* | */ + CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */ +}; /***/ }), -/* 631 */ +/* 619 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(632); -const sync = __webpack_require__(637); -const settings_1 = __webpack_require__(638); -exports.Settings = settings_1.default; -function scandir(path, optionsOrSettingsOrCallback, callback) { - if (typeof optionsOrSettingsOrCallback === 'function') { - return async.read(path, getSettings(), optionsOrSettingsOrCallback); - } - async.read(path, getSettings(optionsOrSettingsOrCallback), callback); -} -exports.scandir = scandir; -function scandirSync(path, optionsOrSettings) { - const settings = getSettings(optionsOrSettings); - return sync.read(path, settings); -} -exports.scandirSync = scandirSync; -function getSettings(settingsOrOptions = {}) { - if (settingsOrOptions instanceof settings_1.default) { - return settingsOrOptions; - } - return new settings_1.default(settingsOrOptions); -} + + +module.exports = __webpack_require__(620); /***/ }), -/* 632 */ +/* 620 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(623); -const rpl = __webpack_require__(633); -const constants_1 = __webpack_require__(634); -const utils = __webpack_require__(635); -function read(dir, settings, callback) { - if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { - return readdirWithFileTypes(dir, settings, callback); - } - return readdir(dir, settings, callback); -} -exports.read = read; -function readdirWithFileTypes(dir, settings, callback) { - settings.fs.readdir(dir, { withFileTypes: true }, (readdirError, dirents) => { - if (readdirError) { - return callFailureCallback(callback, readdirError); - } - const entries = dirents.map((dirent) => ({ - dirent, - name: dirent.name, - path: `${dir}${settings.pathSegmentSeparator}${dirent.name}` - })); - if (!settings.followSymbolicLinks) { - return callSuccessCallback(callback, entries); - } - const tasks = entries.map((entry) => makeRplTaskEntry(entry, settings)); - rpl(tasks, (rplError, rplEntries) => { - if (rplError) { - return callFailureCallback(callback, rplError); - } - callSuccessCallback(callback, rplEntries); - }); - }); -} -exports.readdirWithFileTypes = readdirWithFileTypes; -function makeRplTaskEntry(entry, settings) { - return (done) => { - if (!entry.dirent.isSymbolicLink()) { - return done(null, entry); - } - settings.fs.stat(entry.path, (statError, stats) => { - if (statError) { - if (settings.throwErrorOnBrokenSymbolicLink) { - return done(statError); - } - return done(null, entry); - } - entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); - return done(null, entry); - }); - }; -} -function readdir(dir, settings, callback) { - settings.fs.readdir(dir, (readdirError, names) => { - if (readdirError) { - return callFailureCallback(callback, readdirError); - } - const filepaths = names.map((name) => `${dir}${settings.pathSegmentSeparator}${name}`); - const tasks = filepaths.map((filepath) => { - return (done) => fsStat.stat(filepath, settings.fsStatSettings, done); - }); - rpl(tasks, (rplError, results) => { - if (rplError) { - return callFailureCallback(callback, rplError); - } - const entries = []; - for (let index = 0; index < names.length; index++) { - const name = names[index]; - const stats = results[index]; - const entry = { - name, - path: filepaths[index], - dirent: utils.fs.createDirentFromStats(name, stats) - }; - if (settings.stats) { - entry.stats = stats; - } - entries.push(entry); - } - callSuccessCallback(callback, entries); - }); - }); -} -exports.readdir = readdir; -function callFailureCallback(callback, error) { - callback(error); -} -function callSuccessCallback(callback, result) { - callback(null, result); -} -/***/ }), -/* 633 */ -/***/ (function(module, exports) { +const path = __webpack_require__(16); +const scan = __webpack_require__(621); +const parse = __webpack_require__(624); +const utils = __webpack_require__(622); -module.exports = runParallel +/** + * Creates a matcher function from one or more glob patterns. The + * returned function takes a string to match as its first argument, + * and returns true if the string is a match. The returned matcher + * function also takes a boolean as the second argument that, when true, + * returns an object with additional information. + * + * ```js + * const picomatch = require('picomatch'); + * // picomatch(glob[, options]); + * + * const isMatch = picomatch('*.!(*a)'); + * console.log(isMatch('a.a')); //=> false + * console.log(isMatch('a.b')); //=> true + * ``` + * @name picomatch + * @param {String|Array} `globs` One or more glob patterns. + * @param {Object=} `options` + * @return {Function=} Returns a matcher function. + * @api public + */ -function runParallel (tasks, cb) { - var results, pending, keys - var isSync = true +const picomatch = (glob, options, returnState = false) => { + if (Array.isArray(glob)) { + let fns = glob.map(input => picomatch(input, options, returnState)); + return str => { + for (let isMatch of fns) { + let state = isMatch(str); + if (state) return state; + } + return false; + }; + } - if (Array.isArray(tasks)) { - results = [] - pending = tasks.length - } else { - keys = Object.keys(tasks) - results = {} - pending = keys.length + if (typeof glob !== 'string' || glob === '') { + throw new TypeError('Expected pattern to be a non-empty string'); } - function done (err) { - function end () { - if (cb) cb(err, results) - cb = null - } - if (isSync) process.nextTick(end) - else end() + let opts = options || {}; + let posix = utils.isWindows(options); + let regex = picomatch.makeRe(glob, options, false, true); + let state = regex.state; + delete regex.state; + + let isIgnored = () => false; + if (opts.ignore) { + let ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; + isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); } - function each (i, err, result) { - results[i] = result - if (--pending === 0 || err) { - done(err) + const matcher = (input, returnObject = false) => { + let { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix }); + let result = { glob, state, regex, posix, input, output, match, isMatch }; + + if (typeof opts.onResult === 'function') { + opts.onResult(result); } - } - if (!pending) { - // empty - done(null) - } else if (keys) { - // object - keys.forEach(function (key) { - tasks[key](function (err, result) { each(key, err, result) }) - }) - } else { - // array - tasks.forEach(function (task, i) { - task(function (err, result) { each(i, err, result) }) - }) - } + if (isMatch === false) { + result.isMatch = false; + return returnObject ? result : false; + } - isSync = false -} + if (isIgnored(input)) { + if (typeof opts.onIgnore === 'function') { + opts.onIgnore(result); + } + result.isMatch = false; + return returnObject ? result : false; + } + if (typeof opts.onMatch === 'function') { + opts.onMatch(result); + } + return returnObject ? result : true; + }; -/***/ }), -/* 634 */ -/***/ (function(module, exports, __webpack_require__) { + if (returnState) { + matcher.state = state; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const NODE_PROCESS_VERSION_PARTS = process.versions.node.split('.'); -const MAJOR_VERSION = parseInt(NODE_PROCESS_VERSION_PARTS[0], 10); -const MINOR_VERSION = parseInt(NODE_PROCESS_VERSION_PARTS[1], 10); -/** - * IS `true` for Node.js 10.10 and greater. - */ -exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = MAJOR_VERSION > 10 || (MAJOR_VERSION === 10 && MINOR_VERSION >= 10); + return matcher; +}; +/** + * Test `input` with the given `regex`. This is used by the main + * `picomatch()` function to test the input string. + * + * ```js + * const picomatch = require('picomatch'); + * // picomatch.test(input, regex[, options]); + * + * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/)); + * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' } + * ``` + * @param {String} `input` String to test. + * @param {RegExp} `regex` + * @return {Object} Returns an object with matching info. + * @api public + */ -/***/ }), -/* 635 */ -/***/ (function(module, exports, __webpack_require__) { +picomatch.test = (input, regex, options, { glob, posix } = {}) => { + if (typeof input !== 'string') { + throw new TypeError('Expected input to be a string'); + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(636); -exports.fs = fs; + if (input === '') { + return { isMatch: false, output: '' }; + } + let opts = options || {}; + let format = opts.format || (posix ? utils.toPosixSlashes : null); + let match = input === glob; + let output = (match && format) ? format(input) : input; -/***/ }), -/* 636 */ -/***/ (function(module, exports, __webpack_require__) { + if (match === false) { + output = format ? format(input) : input; + match = output === glob; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -class DirentFromStats { - constructor(name, stats) { - this.name = name; - this.isBlockDevice = stats.isBlockDevice.bind(stats); - this.isCharacterDevice = stats.isCharacterDevice.bind(stats); - this.isDirectory = stats.isDirectory.bind(stats); - this.isFIFO = stats.isFIFO.bind(stats); - this.isFile = stats.isFile.bind(stats); - this.isSocket = stats.isSocket.bind(stats); - this.isSymbolicLink = stats.isSymbolicLink.bind(stats); - } -} -function createDirentFromStats(name, stats) { - return new DirentFromStats(name, stats); -} -exports.createDirentFromStats = createDirentFromStats; + if (match === false || opts.capture === true) { + if (opts.matchBase === true || opts.basename === true) { + match = picomatch.matchBase(input, regex, options, posix); + } else { + match = regex.exec(output); + } + } + return { isMatch: !!match, match, output }; +}; -/***/ }), -/* 637 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(623); -const constants_1 = __webpack_require__(634); -const utils = __webpack_require__(635); -function read(dir, settings) { - if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { - return readdirWithFileTypes(dir, settings); - } - return readdir(dir, settings); -} -exports.read = read; -function readdirWithFileTypes(dir, settings) { - const dirents = settings.fs.readdirSync(dir, { withFileTypes: true }); - return dirents.map((dirent) => { - const entry = { - dirent, - name: dirent.name, - path: `${dir}${settings.pathSegmentSeparator}${dirent.name}` - }; - if (entry.dirent.isSymbolicLink() && settings.followSymbolicLinks) { - try { - const stats = settings.fs.statSync(entry.path); - entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); - } - catch (error) { - if (settings.throwErrorOnBrokenSymbolicLink) { - throw error; - } - } - } - return entry; - }); -} -exports.readdirWithFileTypes = readdirWithFileTypes; -function readdir(dir, settings) { - const names = settings.fs.readdirSync(dir); - return names.map((name) => { - const entryPath = `${dir}${settings.pathSegmentSeparator}${name}`; - const stats = fsStat.statSync(entryPath, settings.fsStatSettings); - const entry = { - name, - path: entryPath, - dirent: utils.fs.createDirentFromStats(name, stats) - }; - if (settings.stats) { - entry.stats = stats; - } - return entry; - }); -} -exports.readdir = readdir; - - -/***/ }), -/* 638 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(16); -const fsStat = __webpack_require__(623); -const fs = __webpack_require__(639); -class Settings { - constructor(_options = {}) { - this._options = _options; - this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, false); - this.fs = fs.createFileSystemAdapter(this._options.fs); - this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); - this.stats = this._getValue(this._options.stats, false); - this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); - this.fsStatSettings = new fsStat.Settings({ - followSymbolicLink: this.followSymbolicLinks, - fs: this.fs, - throwErrorOnBrokenSymbolicLink: this.throwErrorOnBrokenSymbolicLink - }); - } - _getValue(option, value) { - return option === undefined ? value : option; - } -} -exports.default = Settings; +/** + * Match the basename of a filepath. + * + * ```js + * const picomatch = require('picomatch'); + * // picomatch.matchBase(input, glob[, options]); + * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true + * ``` + * @param {String} `input` String to test. + * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe). + * @return {Boolean} + * @api public + */ +picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => { + let regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options); + return regex.test(path.basename(input)); +}; -/***/ }), -/* 639 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * Returns true if **any** of the given glob `patterns` match the specified `string`. + * + * ```js + * const picomatch = require('picomatch'); + * // picomatch.isMatch(string, patterns[, options]); + * + * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true + * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false + * ``` + * @param {String|Array} str The string to test. + * @param {String|Array} patterns One or more glob patterns to use for matching. + * @param {Object} [options] See available [options](#options). + * @return {Boolean} Returns true if any patterns match `str` + * @api public + */ -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(23); -exports.FILE_SYSTEM_ADAPTER = { - lstat: fs.lstat, - stat: fs.stat, - lstatSync: fs.lstatSync, - statSync: fs.statSync, - readdir: fs.readdir, - readdirSync: fs.readdirSync -}; -function createFileSystemAdapter(fsMethods) { - if (!fsMethods) { - return exports.FILE_SYSTEM_ADAPTER; - } - return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); -} -exports.createFileSystemAdapter = createFileSystemAdapter; +picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); +/** + * Parse a glob pattern to create the source string for a regular + * expression. + * + * ```js + * const picomatch = require('picomatch'); + * const result = picomatch.parse(glob[, options]); + * ``` + * @param {String} `glob` + * @param {Object} `options` + * @return {Object} Returns an object with useful properties and output to be used as a regex source string. + * @api public + */ -/***/ }), -/* 640 */ -/***/ (function(module, exports, __webpack_require__) { +picomatch.parse = (glob, options) => parse(glob, options); -"use strict"; +/** + * Scan a glob pattern to separate the pattern into segments. + * + * ```js + * const picomatch = require('picomatch'); + * // picomatch.scan(input[, options]); + * + * const result = picomatch.scan('!./foo/*.js'); + * console.log(result); + * // { prefix: '!./', + * // input: '!./foo/*.js', + * // base: 'foo', + * // glob: '*.js', + * // negated: true, + * // isGlob: true } + * ``` + * @param {String} `input` Glob pattern to scan. + * @param {Object} `options` + * @return {Object} Returns an object with + * @api public + */ +picomatch.scan = (input, options) => scan(input, options); -var reusify = __webpack_require__(641) +/** + * Create a regular expression from a glob pattern. + * + * ```js + * const picomatch = require('picomatch'); + * // picomatch.makeRe(input[, options]); + * + * console.log(picomatch.makeRe('*.js')); + * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ + * ``` + * @param {String} `input` A glob pattern to convert to regex. + * @param {Object} `options` + * @return {RegExp} Returns a regex created from the given pattern. + * @api public + */ -function fastqueue (context, worker, concurrency) { - if (typeof context === 'function') { - concurrency = worker - worker = context - context = null +picomatch.makeRe = (input, options, returnOutput = false, returnState = false) => { + if (!input || typeof input !== 'string') { + throw new TypeError('Expected a non-empty string'); } - var cache = reusify(Task) - var queueHead = null - var queueTail = null - var _running = 0 + let opts = options || {}; + let prepend = opts.contains ? '' : '^'; + let append = opts.contains ? '' : '$'; + let state = { negated: false, fastpaths: true }; + let prefix = ''; + let output; - var self = { - push: push, - drain: noop, - saturated: noop, - pause: pause, - paused: false, - concurrency: concurrency, - running: running, - resume: resume, - idle: idle, - length: length, - unshift: unshift, - empty: noop, - kill: kill, - killAndDrain: killAndDrain + if (input.startsWith('./')) { + input = input.slice(2); + prefix = state.prefix = './'; } - return self - - function running () { - return _running + if (opts.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { + output = parse.fastpaths(input, options); } - function pause () { - self.paused = true + if (output === void 0) { + state = picomatch.parse(input, options); + state.prefix = prefix + (state.prefix || ''); + output = state.output; } - function length () { - var current = queueHead - var counter = 0 - - while (current) { - current = current.next - counter++ - } - - return counter + if (returnOutput === true) { + return output; } - function resume () { - if (!self.paused) return - self.paused = false - for (var i = 0; i < self.concurrency; i++) { - _running++ - release() - } + let source = `${prepend}(?:${output})${append}`; + if (state && state.negated === true) { + source = `^(?!${source}).*$`; } - function idle () { - return _running === 0 && self.length() === 0 + let regex = picomatch.toRegex(source, options); + if (returnState === true) { + regex.state = state; } - function push (value, done) { - var current = cache.get() + return regex; +}; - current.context = context - current.release = release - current.value = value - current.callback = done || noop +/** + * Create a regular expression from the given regex source string. + * + * ```js + * const picomatch = require('picomatch'); + * // picomatch.toRegex(source[, options]); + * + * const { output } = picomatch.parse('*.js'); + * console.log(picomatch.toRegex(output)); + * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ + * ``` + * @param {String} `source` Regular expression source string. + * @param {Object} `options` + * @return {RegExp} + * @api public + */ - if (_running === self.concurrency || self.paused) { - if (queueTail) { - queueTail.next = current - queueTail = current - } else { - queueHead = current - queueTail = current - self.saturated() - } - } else { - _running++ - worker.call(context, current.value, current.worked) - } +picomatch.toRegex = (source, options) => { + try { + let opts = options || {}; + return new RegExp(source, opts.flags || (opts.nocase ? 'i' : '')); + } catch (err) { + if (options && options.debug === true) throw err; + return /$^/; } +}; - function unshift (value, done) { - var current = cache.get() +/** + * Picomatch constants. + * @return {Object} + */ - current.context = context - current.release = release - current.value = value - current.callback = done || noop +picomatch.constants = __webpack_require__(623); - if (_running === self.concurrency || self.paused) { - if (queueHead) { - current.next = queueHead - queueHead = current - } else { - queueHead = current - queueTail = current - self.saturated() - } - } else { - _running++ - worker.call(context, current.value, current.worked) - } - } +/** + * Expose "picomatch" + */ - function release (holder) { - if (holder) { - cache.release(holder) - } - var next = queueHead - if (next) { - if (!self.paused) { - if (queueTail === queueHead) { - queueTail = null - } - queueHead = next.next - next.next = null - worker.call(context, next.value, next.worked) - if (queueTail === null) { - self.empty() - } - } else { - _running-- - } - } else if (--_running === 0) { - self.drain() - } - } +module.exports = picomatch; - function kill () { - queueHead = null - queueTail = null - self.drain = noop - } - function killAndDrain () { - queueHead = null - queueTail = null - self.drain() - self.drain = noop - } -} +/***/ }), +/* 621 */ +/***/ (function(module, exports, __webpack_require__) { -function noop () {} +"use strict"; -function Task () { - this.value = null - this.callback = noop - this.next = null - this.release = noop - this.context = null - var self = this +const utils = __webpack_require__(622); - this.worked = function worked (err, result) { - var callback = self.callback - self.value = null - self.callback = noop - callback.call(self.context, err, result) - self.release(self) - } -} +const { + CHAR_ASTERISK, /* * */ + CHAR_AT, /* @ */ + CHAR_BACKWARD_SLASH, /* \ */ + CHAR_COMMA, /* , */ + CHAR_DOT, /* . */ + CHAR_EXCLAMATION_MARK, /* ! */ + CHAR_FORWARD_SLASH, /* / */ + CHAR_LEFT_CURLY_BRACE, /* { */ + CHAR_LEFT_PARENTHESES, /* ( */ + CHAR_LEFT_SQUARE_BRACKET, /* [ */ + CHAR_PLUS, /* + */ + CHAR_QUESTION_MARK, /* ? */ + CHAR_RIGHT_CURLY_BRACE, /* } */ + CHAR_RIGHT_PARENTHESES, /* ) */ + CHAR_RIGHT_SQUARE_BRACKET /* ] */ +} = __webpack_require__(623); -module.exports = fastqueue +const isPathSeparator = code => { + return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; +}; +/** + * Quickly scans a glob pattern and returns an object with a handful of + * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists), + * `glob` (the actual pattern), and `negated` (true if the path starts with `!`). + * + * ```js + * const pm = require('picomatch'); + * console.log(pm.scan('foo/bar/*.js')); + * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' } + * ``` + * @param {String} `str` + * @param {Object} `options` + * @return {Object} Returns an object with tokens and regex source string. + * @api public + */ -/***/ }), -/* 641 */ -/***/ (function(module, exports, __webpack_require__) { +module.exports = (input, options) => { + let opts = options || {}; + let length = input.length - 1; + let index = -1; + let start = 0; + let lastIndex = 0; + let isGlob = false; + let backslashes = false; + let negated = false; + let braces = 0; + let prev; + let code; -"use strict"; + let braceEscaped = false; + let eos = () => index >= length; + let advance = () => { + prev = code; + return input.charCodeAt(++index); + }; -function reusify (Constructor) { - var head = new Constructor() - var tail = head + while (index < length) { + code = advance(); + let next; - function get () { - var current = head + if (code === CHAR_BACKWARD_SLASH) { + backslashes = true; + next = advance(); - if (current.next) { - head = current.next - } else { - head = new Constructor() - tail = head + if (next === CHAR_LEFT_CURLY_BRACE) { + braceEscaped = true; + } + continue; } - current.next = null + if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { + braces++; - return current - } + while (!eos() && (next = advance())) { + if (next === CHAR_BACKWARD_SLASH) { + backslashes = true; + next = advance(); + continue; + } - function release (obj) { - tail.next = obj - tail = obj - } + if (next === CHAR_LEFT_CURLY_BRACE) { + braces++; + continue; + } - return { - get: get, - release: release - } -} + if (!braceEscaped && next === CHAR_DOT && (next = advance()) === CHAR_DOT) { + isGlob = true; + break; + } -module.exports = reusify + if (!braceEscaped && next === CHAR_COMMA) { + isGlob = true; + break; + } + if (next === CHAR_RIGHT_CURLY_BRACE) { + braces--; + if (braces === 0) { + braceEscaped = false; + break; + } + } + } + } -/***/ }), -/* 642 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function isFatalError(settings, error) { - if (settings.errorFilter === null) { - return true; - } - return !settings.errorFilter(error); -} -exports.isFatalError = isFatalError; -function isAppliedFilter(filter, value) { - return filter === null || filter(value); -} -exports.isAppliedFilter = isAppliedFilter; -function replacePathSegmentSeparator(filepath, separator) { - return filepath.split(/[\\\/]/).join(separator); -} -exports.replacePathSegmentSeparator = replacePathSegmentSeparator; -function joinPathSegments(a, b, separator) { - if (a === '') { - return b; - } - return a + separator + b; -} -exports.joinPathSegments = joinPathSegments; + if (code === CHAR_FORWARD_SLASH) { + if (prev === CHAR_DOT && index === (start + 1)) { + start += 2; + continue; + } + lastIndex = index + 1; + continue; + } -/***/ }), -/* 643 */ -/***/ (function(module, exports, __webpack_require__) { + if (code === CHAR_ASTERISK) { + isGlob = true; + break; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const common = __webpack_require__(642); -class Reader { - constructor(_root, _settings) { - this._root = _root; - this._settings = _settings; - this._root = common.replacePathSegmentSeparator(_root, _settings.pathSegmentSeparator); - } -} -exports.default = Reader; + if (code === CHAR_ASTERISK || code === CHAR_QUESTION_MARK) { + isGlob = true; + break; + } + if (code === CHAR_LEFT_SQUARE_BRACKET) { + while (!eos() && (next = advance())) { + if (next === CHAR_BACKWARD_SLASH) { + backslashes = true; + next = advance(); + continue; + } -/***/ }), -/* 644 */ -/***/ (function(module, exports, __webpack_require__) { + if (next === CHAR_RIGHT_SQUARE_BRACKET) { + isGlob = true; + break; + } + } + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(27); -const async_1 = __webpack_require__(630); -class StreamProvider { - constructor(_root, _settings) { - this._root = _root; - this._settings = _settings; - this._reader = new async_1.default(this._root, this._settings); - this._stream = new stream_1.Readable({ - objectMode: true, - read: () => { }, - destroy: this._reader.destroy.bind(this._reader) - }); - } - read() { - this._reader.onError((error) => { - this._stream.emit('error', error); - }); - this._reader.onEntry((entry) => { - this._stream.push(entry); - }); - this._reader.onEnd(() => { - this._stream.push(null); - }); - this._reader.read(); - return this._stream; - } -} -exports.default = StreamProvider; + let isExtglobChar = code === CHAR_PLUS + || code === CHAR_AT + || code === CHAR_EXCLAMATION_MARK; + if (isExtglobChar && input.charCodeAt(index + 1) === CHAR_LEFT_PARENTHESES) { + isGlob = true; + break; + } -/***/ }), -/* 645 */ -/***/ (function(module, exports, __webpack_require__) { + if (code === CHAR_EXCLAMATION_MARK && index === start) { + negated = true; + start++; + continue; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(646); -class SyncProvider { - constructor(_root, _settings) { - this._root = _root; - this._settings = _settings; - this._reader = new sync_1.default(this._root, this._settings); - } - read() { - return this._reader.read(); - } -} -exports.default = SyncProvider; + if (code === CHAR_LEFT_PARENTHESES) { + while (!eos() && (next = advance())) { + if (next === CHAR_BACKWARD_SLASH) { + backslashes = true; + next = advance(); + continue; + } + if (next === CHAR_RIGHT_PARENTHESES) { + isGlob = true; + break; + } + } + } -/***/ }), -/* 646 */ -/***/ (function(module, exports, __webpack_require__) { + if (isGlob) { + break; + } + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsScandir = __webpack_require__(631); -const common = __webpack_require__(642); -const reader_1 = __webpack_require__(643); -class SyncReader extends reader_1.default { - constructor() { - super(...arguments); - this._scandir = fsScandir.scandirSync; - this._storage = new Set(); - this._queue = new Set(); - } - read() { - this._pushToQueue(this._root, this._settings.basePath); - this._handleQueue(); - return Array.from(this._storage); - } - _pushToQueue(dir, base) { - this._queue.add({ dir, base }); - } - _handleQueue() { - for (const item of this._queue.values()) { - this._handleDirectory(item.dir, item.base); - } - } - _handleDirectory(dir, base) { - try { - const entries = this._scandir(dir, this._settings.fsScandirSettings); - for (const entry of entries) { - this._handleEntry(entry, base); - } - } - catch (error) { - this._handleError(error); - } - } - _handleError(error) { - if (!common.isFatalError(this._settings, error)) { - return; - } - throw error; - } - _handleEntry(entry, base) { - const fullpath = entry.path; - if (base !== undefined) { - entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); - } - if (common.isAppliedFilter(this._settings.entryFilter, entry)) { - this._pushToStorage(entry); - } - if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { - this._pushToQueue(fullpath, entry.path); - } - } - _pushToStorage(entry) { - this._storage.add(entry); - } -} -exports.default = SyncReader; + let prefix = ''; + let orig = input; + let base = input; + let glob = ''; + if (start > 0) { + prefix = input.slice(0, start); + input = input.slice(start); + lastIndex -= start; + } -/***/ }), -/* 647 */ -/***/ (function(module, exports, __webpack_require__) { + if (base && isGlob === true && lastIndex > 0) { + base = input.slice(0, lastIndex); + glob = input.slice(lastIndex); + } else if (isGlob === true) { + base = ''; + glob = input; + } else { + base = input; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(16); -const fsScandir = __webpack_require__(631); -class Settings { - constructor(_options = {}) { - this._options = _options; - this.basePath = this._getValue(this._options.basePath, undefined); - this.concurrency = this._getValue(this._options.concurrency, Infinity); - this.deepFilter = this._getValue(this._options.deepFilter, null); - this.entryFilter = this._getValue(this._options.entryFilter, null); - this.errorFilter = this._getValue(this._options.errorFilter, null); - this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); - this.fsScandirSettings = new fsScandir.Settings({ - followSymbolicLinks: this._options.followSymbolicLinks, - fs: this._options.fs, - pathSegmentSeparator: this._options.pathSegmentSeparator, - stats: this._options.stats, - throwErrorOnBrokenSymbolicLink: this._options.throwErrorOnBrokenSymbolicLink - }); - } - _getValue(option, value) { - return option === undefined ? value : option; - } -} -exports.default = Settings; + if (base && base !== '' && base !== '/' && base !== input) { + if (isPathSeparator(base.charCodeAt(base.length - 1))) { + base = base.slice(0, -1); + } + } + if (opts.unescape === true) { + if (glob) glob = utils.removeBackslashes(glob); -/***/ }), -/* 648 */ -/***/ (function(module, exports, __webpack_require__) { + if (base && backslashes === true) { + base = utils.removeBackslashes(base); + } + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(16); -const fsStat = __webpack_require__(623); -const utils = __webpack_require__(594); -class Reader { - constructor(_settings) { - this._settings = _settings; - this._fsStatSettings = new fsStat.Settings({ - followSymbolicLink: this._settings.followSymbolicLinks, - fs: this._settings.fs, - throwErrorOnBrokenSymbolicLink: this._settings.followSymbolicLinks - }); - } - _getFullEntryPath(filepath) { - return path.resolve(this._settings.cwd, filepath); - } - _makeEntry(stats, pattern) { - const entry = { - name: pattern, - path: pattern, - dirent: utils.fs.createDirentFromStats(pattern, stats) - }; - if (this._settings.stats) { - entry.stats = stats; - } - return entry; - } - _isFatalError(error) { - return !utils.errno.isEnoentCodeError(error) && !this._settings.suppressErrors; - } -} -exports.default = Reader; + return { prefix, input: orig, base, glob, negated, isGlob }; +}; /***/ }), -/* 649 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(16); -const deep_1 = __webpack_require__(650); -const entry_1 = __webpack_require__(651); -const error_1 = __webpack_require__(652); -const entry_2 = __webpack_require__(653); -class Provider { - constructor(_settings) { - this._settings = _settings; - this.errorFilter = new error_1.default(this._settings); - this.entryFilter = new entry_1.default(this._settings, this._getMicromatchOptions()); - this.deepFilter = new deep_1.default(this._settings, this._getMicromatchOptions()); - this.entryTransformer = new entry_2.default(this._settings); - } - _getRootDirectory(task) { - return path.resolve(this._settings.cwd, task.base); - } - _getReaderOptions(task) { - const basePath = task.base === '.' ? '' : task.base; - return { - basePath, - pathSegmentSeparator: '/', - concurrency: this._settings.concurrency, - deepFilter: this.deepFilter.getFilter(basePath, task.positive, task.negative), - entryFilter: this.entryFilter.getFilter(task.positive, task.negative), - errorFilter: this.errorFilter.getFilter(), - followSymbolicLinks: this._settings.followSymbolicLinks, - fs: this._settings.fs, - stats: this._settings.stats, - throwErrorOnBrokenSymbolicLink: this._settings.throwErrorOnBrokenSymbolicLink, - transform: this.entryTransformer.getTransformer() - }; - } - _getMicromatchOptions() { - return { - dot: this._settings.dot, - matchBase: this._settings.baseNameMatch, - nobrace: !this._settings.braceExpansion, - nocase: !this._settings.caseSensitiveMatch, - noext: !this._settings.extglob, - noglobstar: !this._settings.globstar, - posix: true, - strictSlashes: false - }; - } -} -exports.default = Provider; -/***/ }), -/* 650 */ -/***/ (function(module, exports, __webpack_require__) { +const path = __webpack_require__(16); +const win32 = process.platform === 'win32'; +const { + REGEX_SPECIAL_CHARS, + REGEX_SPECIAL_CHARS_GLOBAL, + REGEX_REMOVE_BACKSLASH +} = __webpack_require__(623); -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(594); -class DeepFilter { - constructor(_settings, _micromatchOptions) { - this._settings = _settings; - this._micromatchOptions = _micromatchOptions; - } - getFilter(basePath, positive, negative) { - const maxPatternDepth = this._getMaxPatternDepth(positive); - const negativeRe = this._getNegativePatternsRe(negative); - return (entry) => this._filter(basePath, entry, negativeRe, maxPatternDepth); - } - _getMaxPatternDepth(patterns) { - const globstar = patterns.some(utils.pattern.hasGlobStar); - return globstar ? Infinity : utils.pattern.getMaxNaivePatternsDepth(patterns); - } - _getNegativePatternsRe(patterns) { - const affectDepthOfReadingPatterns = patterns.filter(utils.pattern.isAffectDepthOfReadingPattern); - return utils.pattern.convertPatternsToRe(affectDepthOfReadingPatterns, this._micromatchOptions); - } - _filter(basePath, entry, negativeRe, maxPatternDepth) { - const depth = this._getEntryDepth(basePath, entry.path); - if (this._isSkippedByDeep(depth)) { - return false; - } - if (this._isSkippedByMaxPatternDepth(depth, maxPatternDepth)) { - return false; - } - if (this._isSkippedSymbolicLink(entry)) { - return false; - } - if (this._isSkippedDotDirectory(entry)) { - return false; - } - return this._isSkippedByNegativePatterns(entry, negativeRe); - } - _getEntryDepth(basePath, entryPath) { - const basePathDepth = basePath.split('/').length; - const entryPathDepth = entryPath.split('/').length; - return entryPathDepth - (basePath === '' ? 0 : basePathDepth); - } - _isSkippedByDeep(entryDepth) { - return entryDepth >= this._settings.deep; - } - _isSkippedByMaxPatternDepth(entryDepth, maxPatternDepth) { - return !this._settings.baseNameMatch && maxPatternDepth !== Infinity && entryDepth > maxPatternDepth; - } - _isSkippedSymbolicLink(entry) { - return !this._settings.followSymbolicLinks && entry.dirent.isSymbolicLink(); - } - _isSkippedDotDirectory(entry) { - return !this._settings.dot && entry.name.startsWith('.'); - } - _isSkippedByNegativePatterns(entry, negativeRe) { - return !utils.pattern.matchAny(entry.path, negativeRe); - } -} -exports.default = DeepFilter; +exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); +exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); +exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str); +exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1'); +exports.toPosixSlashes = str => str.replace(/\\/g, '/'); +exports.removeBackslashes = str => { + return str.replace(REGEX_REMOVE_BACKSLASH, match => { + return match === '\\' ? '' : match; + }); +} -/***/ }), -/* 651 */ -/***/ (function(module, exports, __webpack_require__) { +exports.supportsLookbehinds = () => { + let segs = process.version.slice(1).split('.'); + if (segs.length === 3 && +segs[0] >= 9 || (+segs[0] === 8 && +segs[1] >= 10)) { + return true; + } + return false; +}; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(594); -class EntryFilter { - constructor(_settings, _micromatchOptions) { - this._settings = _settings; - this._micromatchOptions = _micromatchOptions; - this.index = new Map(); - } - getFilter(positive, negative) { - const positiveRe = utils.pattern.convertPatternsToRe(positive, this._micromatchOptions); - const negativeRe = utils.pattern.convertPatternsToRe(negative, this._micromatchOptions); - return (entry) => this._filter(entry, positiveRe, negativeRe); - } - _filter(entry, positiveRe, negativeRe) { - if (this._settings.unique) { - if (this._isDuplicateEntry(entry)) { - return false; - } - this._createIndexRecord(entry); - } - if (this._onlyFileFilter(entry) || this._onlyDirectoryFilter(entry)) { - return false; - } - if (this._isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { - return false; - } - const filepath = this._settings.baseNameMatch ? entry.name : entry.path; - return this._isMatchToPatterns(filepath, positiveRe) && !this._isMatchToPatterns(entry.path, negativeRe); - } - _isDuplicateEntry(entry) { - return this.index.has(entry.path); - } - _createIndexRecord(entry) { - this.index.set(entry.path, undefined); - } - _onlyFileFilter(entry) { - return this._settings.onlyFiles && !entry.dirent.isFile(); - } - _onlyDirectoryFilter(entry) { - return this._settings.onlyDirectories && !entry.dirent.isDirectory(); - } - _isSkippedByAbsoluteNegativePatterns(entry, negativeRe) { - if (!this._settings.absolute) { - return false; - } - const fullpath = utils.path.makeAbsolute(this._settings.cwd, entry.path); - return this._isMatchToPatterns(fullpath, negativeRe); - } - _isMatchToPatterns(filepath, patternsRe) { - return utils.pattern.matchAny(filepath, patternsRe); - } -} -exports.default = EntryFilter; +exports.isWindows = options => { + if (options && typeof options.windows === 'boolean') { + return options.windows; + } + return win32 === true || path.sep === '\\'; +}; + +exports.escapeLast = (input, char, lastIdx) => { + let idx = input.lastIndexOf(char, lastIdx); + if (idx === -1) return input; + if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1); + return input.slice(0, idx) + '\\' + input.slice(idx); +}; /***/ }), -/* 652 */ +/* 623 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(594); -class ErrorFilter { - constructor(_settings) { - this._settings = _settings; - } - getFilter() { - return (error) => this._isNonFatalError(error); - } - _isNonFatalError(error) { - return utils.errno.isEnoentCodeError(error) || this._settings.suppressErrors; - } -} -exports.default = ErrorFilter; -/***/ }), +const path = __webpack_require__(16); +const WIN_SLASH = '\\\\/'; +const WIN_NO_SLASH = `[^${WIN_SLASH}]`; + +/** + * Posix glob regex + */ + +const DOT_LITERAL = '\\.'; +const PLUS_LITERAL = '\\+'; +const QMARK_LITERAL = '\\?'; +const SLASH_LITERAL = '\\/'; +const ONE_CHAR = '(?=.)'; +const QMARK = '[^/]'; +const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`; +const START_ANCHOR = `(?:^|${SLASH_LITERAL})`; +const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`; +const NO_DOT = `(?!${DOT_LITERAL})`; +const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`; +const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`; +const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`; +const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`; +const STAR = `${QMARK}*?`; + +const POSIX_CHARS = { + DOT_LITERAL, + PLUS_LITERAL, + QMARK_LITERAL, + SLASH_LITERAL, + ONE_CHAR, + QMARK, + END_ANCHOR, + DOTS_SLASH, + NO_DOT, + NO_DOTS, + NO_DOT_SLASH, + NO_DOTS_SLASH, + QMARK_NO_DOT, + STAR, + START_ANCHOR +}; + +/** + * Windows glob regex + */ + +const WINDOWS_CHARS = { + ...POSIX_CHARS, + + SLASH_LITERAL: `[${WIN_SLASH}]`, + QMARK: WIN_NO_SLASH, + STAR: `${WIN_NO_SLASH}*?`, + DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`, + NO_DOT: `(?!${DOT_LITERAL})`, + NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, + NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`, + NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, + QMARK_NO_DOT: `[^.${WIN_SLASH}]`, + START_ANCHOR: `(?:^|[${WIN_SLASH}])`, + END_ANCHOR: `(?:[${WIN_SLASH}]|$)` +}; + +/** + * POSIX Bracket Regex + */ + +const POSIX_REGEX_SOURCE = { + 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' +}; + +module.exports = { + MAX_LENGTH: 1024 * 64, + POSIX_REGEX_SOURCE, + + // regular expressions + REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g, + REGEX_NON_SPECIAL_CHAR: /^[^@![\].,$*+?^{}()|\\/]+/, + REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/, + REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g, + REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g, + REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g, + + // Replace globs with equivalent patterns to reduce parsing time. + REPLACEMENTS: { + '***': '*', + '**/**': '**', + '**/**/**': '**' + }, + + // Digits + CHAR_0: 48, /* 0 */ + CHAR_9: 57, /* 9 */ + + // Alphabet chars. + CHAR_UPPERCASE_A: 65, /* A */ + CHAR_LOWERCASE_A: 97, /* a */ + CHAR_UPPERCASE_Z: 90, /* Z */ + CHAR_LOWERCASE_Z: 122, /* z */ + + CHAR_LEFT_PARENTHESES: 40, /* ( */ + CHAR_RIGHT_PARENTHESES: 41, /* ) */ + + CHAR_ASTERISK: 42, /* * */ + + // Non-alphabetic chars. + CHAR_AMPERSAND: 38, /* & */ + CHAR_AT: 64, /* @ */ + CHAR_BACKWARD_SLASH: 92, /* \ */ + CHAR_CARRIAGE_RETURN: 13, /* \r */ + CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ + CHAR_COLON: 58, /* : */ + CHAR_COMMA: 44, /* , */ + CHAR_DOT: 46, /* . */ + CHAR_DOUBLE_QUOTE: 34, /* " */ + CHAR_EQUAL: 61, /* = */ + CHAR_EXCLAMATION_MARK: 33, /* ! */ + CHAR_FORM_FEED: 12, /* \f */ + CHAR_FORWARD_SLASH: 47, /* / */ + CHAR_GRAVE_ACCENT: 96, /* ` */ + CHAR_HASH: 35, /* # */ + CHAR_HYPHEN_MINUS: 45, /* - */ + CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ + CHAR_LEFT_CURLY_BRACE: 123, /* { */ + CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ + CHAR_LINE_FEED: 10, /* \n */ + CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ + CHAR_PERCENT: 37, /* % */ + CHAR_PLUS: 43, /* + */ + CHAR_QUESTION_MARK: 63, /* ? */ + CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ + CHAR_RIGHT_CURLY_BRACE: 125, /* } */ + CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ + CHAR_SEMICOLON: 59, /* ; */ + CHAR_SINGLE_QUOTE: 39, /* ' */ + CHAR_SPACE: 32, /* */ + CHAR_TAB: 9, /* \t */ + CHAR_UNDERSCORE: 95, /* _ */ + CHAR_VERTICAL_LINE: 124, /* | */ + CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ + + SEP: path.sep, + + /** + * Create EXTGLOB_CHARS + */ + + extglobChars(chars) { + return { + '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` }, + '?': { type: 'qmark', open: '(?:', close: ')?' }, + '+': { type: 'plus', open: '(?:', close: ')+' }, + '*': { type: 'star', open: '(?:', close: ')*' }, + '@': { type: 'at', open: '(?:', close: ')' } + }; + }, + + /** + * Create GLOB_CHARS + */ + + globChars(win32) { + return win32 === true ? WINDOWS_CHARS : POSIX_CHARS; + } +}; + + +/***/ }), +/* 624 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const utils = __webpack_require__(622); +const constants = __webpack_require__(623); + +/** + * Constants + */ + +const { + MAX_LENGTH, + POSIX_REGEX_SOURCE, + REGEX_NON_SPECIAL_CHAR, + REGEX_SPECIAL_CHARS_BACKREF, + REPLACEMENTS +} = constants; + +/** + * Helpers + */ + +const expandRange = (args, options) => { + if (typeof options.expandRange === 'function') { + return options.expandRange(...args, options); + } + + args.sort(); + let value = `[${args.join('-')}]`; + + try { + /* eslint-disable no-new */ + new RegExp(value); + } catch (ex) { + return args.map(v => utils.escapeRegex(v)).join('..'); + } + + return value; +}; + +const negate = state => { + let count = 1; + + while (state.peek() === '!' && (state.peek(2) !== '(' || state.peek(3) === '?')) { + state.advance(); + state.start++; + count++; + } + + if (count % 2 === 0) { + return false; + } + + state.negated = true; + state.start++; + return true; +}; + +/** + * Create the message for a syntax error + */ + +const syntaxError = (type, char) => { + return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; +}; + +/** + * Parse the given input string. + * @param {String} input + * @param {Object} options + * @return {Object} + */ + +const parse = (input, options) => { + if (typeof input !== 'string') { + throw new TypeError('Expected a string'); + } + + input = REPLACEMENTS[input] || input; + + let opts = { ...options }; + let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; + let len = input.length; + if (len > max) { + throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); + } + + let bos = { type: 'bos', value: '', output: opts.prepend || '' }; + let tokens = [bos]; + + let capture = opts.capture ? '' : '?:'; + let win32 = utils.isWindows(options); + + // create constants based on platform, for windows or posix + const PLATFORM_CHARS = constants.globChars(win32); + const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS); + + const { + DOT_LITERAL, + PLUS_LITERAL, + SLASH_LITERAL, + ONE_CHAR, + DOTS_SLASH, + NO_DOT, + NO_DOT_SLASH, + NO_DOTS_SLASH, + QMARK, + QMARK_NO_DOT, + STAR, + START_ANCHOR + } = PLATFORM_CHARS; + + const globstar = (opts) => { + return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; + }; + + let nodot = opts.dot ? '' : NO_DOT; + let star = opts.bash === true ? globstar(opts) : STAR; + let qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT; + + if (opts.capture) { + star = `(${star})`; + } + + // minimatch options support + if (typeof opts.noext === 'boolean') { + opts.noextglob = opts.noext; + } + + let state = { + index: -1, + start: 0, + consumed: '', + output: '', + backtrack: false, + brackets: 0, + braces: 0, + parens: 0, + quotes: 0, + tokens + }; + + let extglobs = []; + let stack = []; + let prev = bos; + let value; + + /** + * Tokenizing helpers + */ + + const eos = () => state.index === len - 1; + const peek = state.peek = (n = 1) => input[state.index + n]; + const advance = state.advance = () => input[++state.index]; + const append = token => { + state.output += token.output != null ? token.output : token.value; + state.consumed += token.value || ''; + }; + + const increment = type => { + state[type]++; + stack.push(type); + }; + + const decrement = type => { + state[type]--; + stack.pop(); + }; + + /** + * Push tokens onto the tokens array. This helper speeds up + * tokenizing by 1) helping us avoid backtracking as much as possible, + * and 2) helping us avoid creating extra tokens when consecutive + * characters are plain text. This improves performance and simplifies + * lookbehinds. + */ + + const push = tok => { + if (prev.type === 'globstar') { + let isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace'); + let isExtglob = extglobs.length && (tok.type === 'pipe' || tok.type === 'paren'); + if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) { + state.output = state.output.slice(0, -prev.output.length); + prev.type = 'star'; + prev.value = '*'; + prev.output = star; + state.output += prev.output; + } + } + + if (extglobs.length && tok.type !== 'paren' && !EXTGLOB_CHARS[tok.value]) { + extglobs[extglobs.length - 1].inner += tok.value; + } + + if (tok.value || tok.output) append(tok); + if (prev && prev.type === 'text' && tok.type === 'text') { + prev.value += tok.value; + return; + } + + tok.prev = prev; + tokens.push(tok); + prev = tok; + }; + + const extglobOpen = (type, value) => { + let token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' }; + + token.prev = prev; + token.parens = state.parens; + token.output = state.output; + let output = (opts.capture ? '(' : '') + token.open; + + push({ type, value, output: state.output ? '' : ONE_CHAR }); + push({ type: 'paren', extglob: true, value: advance(), output }); + increment('parens'); + extglobs.push(token); + }; + + const extglobClose = token => { + let output = token.close + (opts.capture ? ')' : ''); + + if (token.type === 'negate') { + let extglobStar = star; + + if (token.inner && token.inner.length > 1 && token.inner.includes('/')) { + extglobStar = globstar(opts); + } + + if (extglobStar !== star || eos() || /^\)+$/.test(input.slice(state.index + 1))) { + output = token.close = ')$))' + extglobStar; + } + + if (token.prev.type === 'bos' && eos()) { + state.negatedExtglob = true; + } + } + + push({ type: 'paren', extglob: true, value, output }); + decrement('parens'); + }; + + if (opts.fastpaths !== false && !/(^[*!]|[/{[()\]}"])/.test(input)) { + let backslashes = false; + + let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => { + if (first === '\\') { + backslashes = true; + return m; + } + + if (first === '?') { + if (esc) { + return esc + first + (rest ? QMARK.repeat(rest.length) : ''); + } + if (index === 0) { + return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : ''); + } + return QMARK.repeat(chars.length); + } + + if (first === '.') { + return DOT_LITERAL.repeat(chars.length); + } + + if (first === '*') { + if (esc) { + return esc + first + (rest ? star : ''); + } + return star; + } + return esc ? m : '\\' + m; + }); + + if (backslashes === true) { + if (opts.unescape === true) { + output = output.replace(/\\/g, ''); + } else { + output = output.replace(/\\+/g, m => { + return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : ''); + }); + } + } + + state.output = output; + return state; + } + + /** + * Tokenize input until we reach end-of-string + */ + + while (!eos()) { + value = advance(); + + if (value === '\u0000') { + continue; + } + + /** + * Escaped characters + */ + + if (value === '\\') { + let next = peek(); + + if (next === '/' && opts.bash !== true) { + continue; + } + + if (next === '.' || next === ';') { + continue; + } + + if (!next) { + value += '\\'; + push({ type: 'text', value }); + continue; + } + + // collapse slashes to reduce potential for exploits + let match = /^\\+/.exec(input.slice(state.index + 1)); + let slashes = 0; + + if (match && match[0].length > 2) { + slashes = match[0].length; + state.index += slashes; + if (slashes % 2 !== 0) { + value += '\\'; + } + } + + if (opts.unescape === true) { + value = advance() || ''; + } else { + value += advance() || ''; + } + + if (state.brackets === 0) { + push({ type: 'text', value }); + continue; + } + } + + /** + * If we're inside a regex character class, continue + * until we reach the closing bracket. + */ + + if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) { + if (opts.posix !== false && value === ':') { + let inner = prev.value.slice(1); + if (inner.includes('[')) { + prev.posix = true; + + if (inner.includes(':')) { + let idx = prev.value.lastIndexOf('['); + let pre = prev.value.slice(0, idx); + let rest = prev.value.slice(idx + 2); + let posix = POSIX_REGEX_SOURCE[rest]; + if (posix) { + prev.value = pre + posix; + state.backtrack = true; + advance(); + + if (!bos.output && tokens.indexOf(prev) === 1) { + bos.output = ONE_CHAR; + } + continue; + } + } + } + } + + if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) { + value = '\\' + value; + } + + if (value === ']' && (prev.value === '[' || prev.value === '[^')) { + value = '\\' + value; + } + + if (opts.posix === true && value === '!' && prev.value === '[') { + value = '^'; + } + + prev.value += value; + append({ value }); + continue; + } + + /** + * If we're inside a quoted string, continue + * until we reach the closing double quote. + */ + + if (state.quotes === 1 && value !== '"') { + value = utils.escapeRegex(value); + prev.value += value; + append({ value }); + continue; + } + + /** + * Double quotes + */ + + if (value === '"') { + state.quotes = state.quotes === 1 ? 0 : 1; + if (opts.keepQuotes === true) { + push({ type: 'text', value }); + } + continue; + } + + /** + * Parentheses + */ + + if (value === '(') { + push({ type: 'paren', value }); + increment('parens'); + continue; + } + + if (value === ')') { + if (state.parens === 0 && opts.strictBrackets === true) { + throw new SyntaxError(syntaxError('opening', '(')); + } + + let extglob = extglobs[extglobs.length - 1]; + if (extglob && state.parens === extglob.parens + 1) { + extglobClose(extglobs.pop()); + continue; + } + + push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); + decrement('parens'); + continue; + } + + /** + * Brackets + */ + + if (value === '[') { + if (opts.nobracket === true || !input.slice(state.index + 1).includes(']')) { + if (opts.nobracket !== true && opts.strictBrackets === true) { + throw new SyntaxError(syntaxError('closing', ']')); + } + + value = '\\' + value; + } else { + increment('brackets'); + } + + push({ type: 'bracket', value }); + continue; + } + + if (value === ']') { + if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) { + push({ type: 'text', value, output: '\\' + value }); + continue; + } + + if (state.brackets === 0) { + if (opts.strictBrackets === true) { + throw new SyntaxError(syntaxError('opening', '[')); + } + + push({ type: 'text', value, output: '\\' + value }); + continue; + } + + decrement('brackets'); + + let prevValue = prev.value.slice(1); + if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) { + value = '/' + value; + } + + prev.value += value; + append({ value }); + + // when literal brackets are explicitly disabled + // assume we should match with a regex character class + if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) { + continue; + } + + let escaped = utils.escapeRegex(prev.value); + state.output = state.output.slice(0, -prev.value.length); + + // when literal brackets are explicitly enabled + // assume we should escape the brackets to match literal characters + if (opts.literalBrackets === true) { + state.output += escaped; + prev.value = escaped; + continue; + } + + // when the user specifies nothing, try to match both + prev.value = `(${capture}${escaped}|${prev.value})`; + state.output += prev.value; + continue; + } + + /** + * Braces + */ + + if (value === '{' && opts.nobrace !== true) { + push({ type: 'brace', value, output: '(' }); + increment('braces'); + continue; + } + + if (value === '}') { + if (opts.nobrace === true || state.braces === 0) { + push({ type: 'text', value, output: '\\' + value }); + continue; + } + + let output = ')'; + + if (state.dots === true) { + let arr = tokens.slice(); + let range = []; + + for (let i = arr.length - 1; i >= 0; i--) { + tokens.pop(); + if (arr[i].type === 'brace') { + break; + } + if (arr[i].type !== 'dots') { + range.unshift(arr[i].value); + } + } + + output = expandRange(range, opts); + state.backtrack = true; + } + + push({ type: 'brace', value, output }); + decrement('braces'); + continue; + } + + /** + * Pipes + */ + + if (value === '|') { + if (extglobs.length > 0) { + extglobs[extglobs.length - 1].conditions++; + } + push({ type: 'text', value }); + continue; + } + + /** + * Commas + */ + + if (value === ',') { + let output = value; + + if (state.braces > 0 && stack[stack.length - 1] === 'braces') { + output = '|'; + } + + push({ type: 'comma', value, output }); + continue; + } + + /** + * Slashes + */ + + if (value === '/') { + // if the beginning of the glob is "./", advance the start + // to the current index, and don't add the "./" characters + // to the state. This greatly simplifies lookbehinds when + // checking for BOS characters like "!" and "." (not "./") + if (prev.type === 'dot' && state.index === 1) { + state.start = state.index + 1; + state.consumed = ''; + state.output = ''; + tokens.pop(); + prev = bos; // reset "prev" to the first token + continue; + } + + push({ type: 'slash', value, output: SLASH_LITERAL }); + continue; + } + + /** + * Dots + */ + + if (value === '.') { + if (state.braces > 0 && prev.type === 'dot') { + if (prev.value === '.') prev.output = DOT_LITERAL; + prev.type = 'dots'; + prev.output += value; + prev.value += value; + state.dots = true; + continue; + } + + push({ type: 'dot', value, output: DOT_LITERAL }); + continue; + } + + /** + * Question marks + */ + + if (value === '?') { + if (prev && prev.type === 'paren') { + let next = peek(); + let output = value; + + if (next === '<' && !utils.supportsLookbehinds()) { + throw new Error('Node.js v10 or higher is required for regex lookbehinds'); + } + + if (prev.value === '(' && !/[!=<:]/.test(next) || (next === '<' && !/[!=]/.test(peek(2)))) { + output = '\\' + value; + } + + push({ type: 'text', value, output }); + continue; + } + + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + extglobOpen('qmark', value); + continue; + } + + if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { + push({ type: 'qmark', value, output: QMARK_NO_DOT }); + continue; + } + + push({ type: 'qmark', value, output: QMARK }); + continue; + } + + /** + * Exclamation + */ + + if (value === '!') { + if (opts.noextglob !== true && peek() === '(') { + if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) { + extglobOpen('negate', value); + continue; + } + } + + if (opts.nonegate !== true && state.index === 0) { + negate(state); + continue; + } + } + + /** + * Plus + */ + + if (value === '+') { + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + extglobOpen('plus', value); + continue; + } + + if (prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) { + let output = prev.extglob === true ? '\\' + value : value; + push({ type: 'plus', value, output }); + continue; + } + + // use regex behavior inside parens + if (state.parens > 0 && opts.regex !== false) { + push({ type: 'plus', value }); + continue; + } + + push({ type: 'plus', value: PLUS_LITERAL }); + continue; + } + + /** + * Plain text + */ + + if (value === '@') { + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + push({ type: 'at', value, output: '' }); + continue; + } + + push({ type: 'text', value }); + continue; + } + + /** + * Plain text + */ + + if (value !== '*') { + if (value === '$' || value === '^') { + value = '\\' + value; + } + + let match = REGEX_NON_SPECIAL_CHAR.exec(input.slice(state.index + 1)); + if (match) { + value += match[0]; + state.index += match[0].length; + } + + push({ type: 'text', value }); + continue; + } + + /** + * Stars + */ + + if (prev && (prev.type === 'globstar' || prev.star === true)) { + prev.type = 'star'; + prev.star = true; + prev.value += value; + prev.output = star; + state.backtrack = true; + state.consumed += value; + continue; + } + + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + extglobOpen('star', value); + continue; + } + + if (prev.type === 'star') { + if (opts.noglobstar === true) { + state.consumed += value; + continue; + } + + let prior = prev.prev; + let before = prior.prev; + let isStart = prior.type === 'slash' || prior.type === 'bos'; + let afterStar = before && (before.type === 'star' || before.type === 'globstar'); + + if (opts.bash === true && (!isStart || (!eos() && peek() !== '/'))) { + push({ type: 'star', value, output: '' }); + continue; + } + + let isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace'); + let isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren'); + if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) { + push({ type: 'star', value, output: '' }); + continue; + } + + // strip consecutive `/**/` + while (input.slice(state.index + 1, state.index + 4) === '/**') { + let after = input[state.index + 4]; + if (after && after !== '/') { + break; + } + state.consumed += '/**'; + state.index += 3; + } + + if (prior.type === 'bos' && eos()) { + prev.type = 'globstar'; + prev.value += value; + prev.output = globstar(opts); + state.output = prev.output; + state.consumed += value; + continue; + } + + if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) { + state.output = state.output.slice(0, -(prior.output + prev.output).length); + prior.output = '(?:' + prior.output; + + prev.type = 'globstar'; + prev.output = globstar(opts) + '|$)'; + prev.value += value; + + state.output += prior.output + prev.output; + state.consumed += value; + continue; + } + + let next = peek(); + if (prior.type === 'slash' && prior.prev.type !== 'bos' && next === '/') { + let end = peek(2) !== void 0 ? '|$' : ''; + + state.output = state.output.slice(0, -(prior.output + prev.output).length); + prior.output = '(?:' + prior.output; + + prev.type = 'globstar'; + prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; + prev.value += value; + + state.output += prior.output + prev.output; + state.consumed += value + advance(); + + push({ type: 'slash', value, output: '' }); + continue; + } + + if (prior.type === 'bos' && next === '/') { + prev.type = 'globstar'; + prev.value += value; + prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`; + state.output = prev.output; + state.consumed += value + advance(); + push({ type: 'slash', value, output: '' }); + continue; + } + + // remove single star from output + state.output = state.output.slice(0, -prev.output.length); + + // reset previous token to globstar + prev.type = 'globstar'; + prev.output = globstar(opts); + prev.value += value; + + // reset output with globstar + state.output += prev.output; + state.consumed += value; + continue; + } + + let token = { type: 'star', value, output: star }; + + if (opts.bash === true) { + token.output = '.*?'; + if (prev.type === 'bos' || prev.type === 'slash') { + token.output = nodot + token.output; + } + push(token); + continue; + } + + if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) { + token.output = value; + push(token); + continue; + } + + if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') { + if (prev.type === 'dot') { + state.output += NO_DOT_SLASH; + prev.output += NO_DOT_SLASH; + + } else if (opts.dot === true) { + state.output += NO_DOTS_SLASH; + prev.output += NO_DOTS_SLASH; + + } else { + state.output += nodot; + prev.output += nodot; + } + + if (peek() !== '*') { + state.output += ONE_CHAR; + prev.output += ONE_CHAR; + } + } + + push(token); + } + + while (state.brackets > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']')); + state.output = utils.escapeLast(state.output, '['); + decrement('brackets'); + } + + while (state.parens > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')')); + state.output = utils.escapeLast(state.output, '('); + decrement('parens'); + } + + while (state.braces > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}')); + state.output = utils.escapeLast(state.output, '{'); + decrement('braces'); + } + + if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) { + push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); + } + + // rebuild the output if we had to backtrack at any point + if (state.backtrack === true) { + state.output = ''; + + for (let token of state.tokens) { + state.output += token.output != null ? token.output : token.value; + + if (token.suffix) { + state.output += token.suffix; + } + } + } + + return state; +}; + +/** + * Fast paths for creating regular expressions for common glob patterns. + * This can significantly speed up processing and has very little downside + * impact when none of the fast paths match. + */ + +parse.fastpaths = (input, options) => { + let opts = { ...options }; + let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; + let len = input.length; + if (len > max) { + throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); + } + + input = REPLACEMENTS[input] || input; + let win32 = utils.isWindows(options); + + // create constants based on platform, for windows or posix + const { + DOT_LITERAL, + SLASH_LITERAL, + ONE_CHAR, + DOTS_SLASH, + NO_DOT, + NO_DOTS, + NO_DOTS_SLASH, + STAR, + START_ANCHOR + } = constants.globChars(win32); + + let capture = opts.capture ? '' : '?:'; + let star = opts.bash === true ? '.*?' : STAR; + let nodot = opts.dot ? NO_DOTS : NO_DOT; + let slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT; + + if (opts.capture) { + star = `(${star})`; + } + + const globstar = (opts) => { + return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; + }; + + const create = str => { + switch (str) { + case '*': + return `${nodot}${ONE_CHAR}${star}`; + + case '.*': + return `${DOT_LITERAL}${ONE_CHAR}${star}`; + + case '*.*': + return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; + + case '*/*': + return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`; + + case '**': + return nodot + globstar(opts); + + case '**/*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`; + + case '**/*.*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; + + case '**/.*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`; + + default: { + let match = /^(.*?)\.(\w+)$/.exec(str); + if (!match) return; + + let source = create(match[1], options); + if (!source) return; + + return source + DOT_LITERAL + match[2]; + } + } + }; + + let output = create(input); + if (output && opts.strictSlashes !== true) { + output += `${SLASH_LITERAL}?`; + } + + return output; +}; + +module.exports = parse; + + +/***/ }), +/* 625 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const merge2 = __webpack_require__(591); +function merge(streams) { + const mergedStream = merge2(streams); + streams.forEach((stream) => { + stream.once('error', (err) => mergedStream.emit('error', err)); + }); + return mergedStream; +} +exports.merge = merge; + + +/***/ }), +/* 626 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const stream_1 = __webpack_require__(627); +const provider_1 = __webpack_require__(654); +class ProviderAsync extends provider_1.default { + constructor() { + super(...arguments); + this._reader = new stream_1.default(this._settings); + } + read(task) { + const root = this._getRootDirectory(task); + const options = this._getReaderOptions(task); + const entries = []; + return new Promise((resolve, reject) => { + const stream = this.api(root, task, options); + stream.once('error', reject); + stream.on('data', (entry) => entries.push(options.transform(entry))); + stream.once('end', () => resolve(entries)); + }); + } + api(root, task, options) { + if (task.dynamic) { + return this._reader.dynamic(root, options); + } + return this._reader.static(task.patterns, options); + } +} +exports.default = ProviderAsync; + + +/***/ }), +/* 627 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const stream_1 = __webpack_require__(27); +const fsStat = __webpack_require__(628); +const fsWalk = __webpack_require__(633); +const reader_1 = __webpack_require__(653); +class ReaderStream extends reader_1.default { + constructor() { + super(...arguments); + this._walkStream = fsWalk.walkStream; + this._stat = fsStat.stat; + } + dynamic(root, options) { + return this._walkStream(root, options); + } + static(patterns, options) { + const filepaths = patterns.map(this._getFullEntryPath, this); + const stream = new stream_1.PassThrough({ objectMode: true }); + stream._write = (index, _enc, done) => { + return this._getEntry(filepaths[index], patterns[index], options) + .then((entry) => { + if (entry !== null && options.entryFilter(entry)) { + stream.push(entry); + } + if (index === filepaths.length - 1) { + stream.end(); + } + done(); + }) + .catch(done); + }; + for (let i = 0; i < filepaths.length; i++) { + stream.write(i); + } + return stream; + } + _getEntry(filepath, pattern, options) { + return this._getStat(filepath) + .then((stats) => this._makeEntry(stats, pattern)) + .catch((error) => { + if (options.errorFilter(error)) { + return null; + } + throw error; + }); + } + _getStat(filepath) { + return new Promise((resolve, reject) => { + this._stat(filepath, this._fsStatSettings, (error, stats) => { + error ? reject(error) : resolve(stats); + }); + }); + } +} +exports.default = ReaderStream; + + +/***/ }), +/* 628 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const async = __webpack_require__(629); +const sync = __webpack_require__(630); +const settings_1 = __webpack_require__(631); +exports.Settings = settings_1.default; +function stat(path, optionsOrSettingsOrCallback, callback) { + if (typeof optionsOrSettingsOrCallback === 'function') { + return async.read(path, getSettings(), optionsOrSettingsOrCallback); + } + async.read(path, getSettings(optionsOrSettingsOrCallback), callback); +} +exports.stat = stat; +function statSync(path, optionsOrSettings) { + const settings = getSettings(optionsOrSettings); + return sync.read(path, settings); +} +exports.statSync = statSync; +function getSettings(settingsOrOptions = {}) { + if (settingsOrOptions instanceof settings_1.default) { + return settingsOrOptions; + } + return new settings_1.default(settingsOrOptions); +} + + +/***/ }), +/* 629 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function read(path, settings, callback) { + settings.fs.lstat(path, (lstatError, lstat) => { + if (lstatError) { + return callFailureCallback(callback, lstatError); + } + if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { + return callSuccessCallback(callback, lstat); + } + settings.fs.stat(path, (statError, stat) => { + if (statError) { + if (settings.throwErrorOnBrokenSymbolicLink) { + return callFailureCallback(callback, statError); + } + return callSuccessCallback(callback, lstat); + } + if (settings.markSymbolicLink) { + stat.isSymbolicLink = () => true; + } + callSuccessCallback(callback, stat); + }); + }); +} +exports.read = read; +function callFailureCallback(callback, error) { + callback(error); +} +function callSuccessCallback(callback, result) { + callback(null, result); +} + + +/***/ }), +/* 630 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function read(path, settings) { + const lstat = settings.fs.lstatSync(path); + if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { + return lstat; + } + try { + const stat = settings.fs.statSync(path); + if (settings.markSymbolicLink) { + stat.isSymbolicLink = () => true; + } + return stat; + } + catch (error) { + if (!settings.throwErrorOnBrokenSymbolicLink) { + return lstat; + } + throw error; + } +} +exports.read = read; + + +/***/ }), +/* 631 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(632); +class Settings { + constructor(_options = {}) { + this._options = _options; + this.followSymbolicLink = this._getValue(this._options.followSymbolicLink, true); + this.fs = fs.createFileSystemAdapter(this._options.fs); + this.markSymbolicLink = this._getValue(this._options.markSymbolicLink, false); + this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); + } + _getValue(option, value) { + return option === undefined ? value : option; + } +} +exports.default = Settings; + + +/***/ }), +/* 632 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(23); +exports.FILE_SYSTEM_ADAPTER = { + lstat: fs.lstat, + stat: fs.stat, + lstatSync: fs.lstatSync, + statSync: fs.statSync +}; +function createFileSystemAdapter(fsMethods) { + if (!fsMethods) { + return exports.FILE_SYSTEM_ADAPTER; + } + return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); +} +exports.createFileSystemAdapter = createFileSystemAdapter; + + +/***/ }), +/* 633 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const async_1 = __webpack_require__(634); +const stream_1 = __webpack_require__(649); +const sync_1 = __webpack_require__(650); +const settings_1 = __webpack_require__(652); +exports.Settings = settings_1.default; +function walk(dir, optionsOrSettingsOrCallback, callback) { + if (typeof optionsOrSettingsOrCallback === 'function') { + return new async_1.default(dir, getSettings()).read(optionsOrSettingsOrCallback); + } + new async_1.default(dir, getSettings(optionsOrSettingsOrCallback)).read(callback); +} +exports.walk = walk; +function walkSync(dir, optionsOrSettings) { + const settings = getSettings(optionsOrSettings); + const provider = new sync_1.default(dir, settings); + return provider.read(); +} +exports.walkSync = walkSync; +function walkStream(dir, optionsOrSettings) { + const settings = getSettings(optionsOrSettings); + const provider = new stream_1.default(dir, settings); + return provider.read(); +} +exports.walkStream = walkStream; +function getSettings(settingsOrOptions = {}) { + if (settingsOrOptions instanceof settings_1.default) { + return settingsOrOptions; + } + return new settings_1.default(settingsOrOptions); +} + + +/***/ }), +/* 634 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const async_1 = __webpack_require__(635); +class AsyncProvider { + constructor(_root, _settings) { + this._root = _root; + this._settings = _settings; + this._reader = new async_1.default(this._root, this._settings); + this._storage = new Set(); + } + read(callback) { + this._reader.onError((error) => { + callFailureCallback(callback, error); + }); + this._reader.onEntry((entry) => { + this._storage.add(entry); + }); + this._reader.onEnd(() => { + callSuccessCallback(callback, Array.from(this._storage)); + }); + this._reader.read(); + } +} +exports.default = AsyncProvider; +function callFailureCallback(callback, error) { + callback(error); +} +function callSuccessCallback(callback, entries) { + callback(null, entries); +} + + +/***/ }), +/* 635 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const events_1 = __webpack_require__(379); +const fsScandir = __webpack_require__(636); +const fastq = __webpack_require__(645); +const common = __webpack_require__(647); +const reader_1 = __webpack_require__(648); +class AsyncReader extends reader_1.default { + constructor(_root, _settings) { + super(_root, _settings); + this._settings = _settings; + this._scandir = fsScandir.scandir; + this._emitter = new events_1.EventEmitter(); + this._queue = fastq(this._worker.bind(this), this._settings.concurrency); + this._isFatalError = false; + this._isDestroyed = false; + this._queue.drain = () => { + if (!this._isFatalError) { + this._emitter.emit('end'); + } + }; + } + read() { + this._isFatalError = false; + this._isDestroyed = false; + setImmediate(() => { + this._pushToQueue(this._root, this._settings.basePath); + }); + return this._emitter; + } + destroy() { + if (this._isDestroyed) { + throw new Error('The reader is already destroyed'); + } + this._isDestroyed = true; + this._queue.killAndDrain(); + } + onEntry(callback) { + this._emitter.on('entry', callback); + } + onError(callback) { + this._emitter.once('error', callback); + } + onEnd(callback) { + this._emitter.once('end', callback); + } + _pushToQueue(dir, base) { + const queueItem = { dir, base }; + this._queue.push(queueItem, (error) => { + if (error) { + this._handleError(error); + } + }); + } + _worker(item, done) { + this._scandir(item.dir, this._settings.fsScandirSettings, (error, entries) => { + if (error) { + return done(error, undefined); + } + for (const entry of entries) { + this._handleEntry(entry, item.base); + } + done(null, undefined); + }); + } + _handleError(error) { + if (!common.isFatalError(this._settings, error)) { + return; + } + this._isFatalError = true; + this._isDestroyed = true; + this._emitter.emit('error', error); + } + _handleEntry(entry, base) { + if (this._isDestroyed || this._isFatalError) { + return; + } + const fullpath = entry.path; + if (base !== undefined) { + entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); + } + if (common.isAppliedFilter(this._settings.entryFilter, entry)) { + this._emitEntry(entry); + } + if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { + this._pushToQueue(fullpath, entry.path); + } + } + _emitEntry(entry) { + this._emitter.emit('entry', entry); + } +} +exports.default = AsyncReader; + + +/***/ }), +/* 636 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const async = __webpack_require__(637); +const sync = __webpack_require__(642); +const settings_1 = __webpack_require__(643); +exports.Settings = settings_1.default; +function scandir(path, optionsOrSettingsOrCallback, callback) { + if (typeof optionsOrSettingsOrCallback === 'function') { + return async.read(path, getSettings(), optionsOrSettingsOrCallback); + } + async.read(path, getSettings(optionsOrSettingsOrCallback), callback); +} +exports.scandir = scandir; +function scandirSync(path, optionsOrSettings) { + const settings = getSettings(optionsOrSettings); + return sync.read(path, settings); +} +exports.scandirSync = scandirSync; +function getSettings(settingsOrOptions = {}) { + if (settingsOrOptions instanceof settings_1.default) { + return settingsOrOptions; + } + return new settings_1.default(settingsOrOptions); +} + + +/***/ }), +/* 637 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsStat = __webpack_require__(628); +const rpl = __webpack_require__(638); +const constants_1 = __webpack_require__(639); +const utils = __webpack_require__(640); +function read(dir, settings, callback) { + if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { + return readdirWithFileTypes(dir, settings, callback); + } + return readdir(dir, settings, callback); +} +exports.read = read; +function readdirWithFileTypes(dir, settings, callback) { + settings.fs.readdir(dir, { withFileTypes: true }, (readdirError, dirents) => { + if (readdirError) { + return callFailureCallback(callback, readdirError); + } + const entries = dirents.map((dirent) => ({ + dirent, + name: dirent.name, + path: `${dir}${settings.pathSegmentSeparator}${dirent.name}` + })); + if (!settings.followSymbolicLinks) { + return callSuccessCallback(callback, entries); + } + const tasks = entries.map((entry) => makeRplTaskEntry(entry, settings)); + rpl(tasks, (rplError, rplEntries) => { + if (rplError) { + return callFailureCallback(callback, rplError); + } + callSuccessCallback(callback, rplEntries); + }); + }); +} +exports.readdirWithFileTypes = readdirWithFileTypes; +function makeRplTaskEntry(entry, settings) { + return (done) => { + if (!entry.dirent.isSymbolicLink()) { + return done(null, entry); + } + settings.fs.stat(entry.path, (statError, stats) => { + if (statError) { + if (settings.throwErrorOnBrokenSymbolicLink) { + return done(statError); + } + return done(null, entry); + } + entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); + return done(null, entry); + }); + }; +} +function readdir(dir, settings, callback) { + settings.fs.readdir(dir, (readdirError, names) => { + if (readdirError) { + return callFailureCallback(callback, readdirError); + } + const filepaths = names.map((name) => `${dir}${settings.pathSegmentSeparator}${name}`); + const tasks = filepaths.map((filepath) => { + return (done) => fsStat.stat(filepath, settings.fsStatSettings, done); + }); + rpl(tasks, (rplError, results) => { + if (rplError) { + return callFailureCallback(callback, rplError); + } + const entries = []; + for (let index = 0; index < names.length; index++) { + const name = names[index]; + const stats = results[index]; + const entry = { + name, + path: filepaths[index], + dirent: utils.fs.createDirentFromStats(name, stats) + }; + if (settings.stats) { + entry.stats = stats; + } + entries.push(entry); + } + callSuccessCallback(callback, entries); + }); + }); +} +exports.readdir = readdir; +function callFailureCallback(callback, error) { + callback(error); +} +function callSuccessCallback(callback, result) { + callback(null, result); +} + + +/***/ }), +/* 638 */ +/***/ (function(module, exports) { + +module.exports = runParallel + +function runParallel (tasks, cb) { + var results, pending, keys + var isSync = true + + if (Array.isArray(tasks)) { + results = [] + pending = tasks.length + } else { + keys = Object.keys(tasks) + results = {} + pending = keys.length + } + + function done (err) { + function end () { + if (cb) cb(err, results) + cb = null + } + if (isSync) process.nextTick(end) + else end() + } + + function each (i, err, result) { + results[i] = result + if (--pending === 0 || err) { + done(err) + } + } + + if (!pending) { + // empty + done(null) + } else if (keys) { + // object + keys.forEach(function (key) { + tasks[key](function (err, result) { each(key, err, result) }) + }) + } else { + // array + tasks.forEach(function (task, i) { + task(function (err, result) { each(i, err, result) }) + }) + } + + isSync = false +} + + +/***/ }), +/* 639 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const NODE_PROCESS_VERSION_PARTS = process.versions.node.split('.'); +const MAJOR_VERSION = parseInt(NODE_PROCESS_VERSION_PARTS[0], 10); +const MINOR_VERSION = parseInt(NODE_PROCESS_VERSION_PARTS[1], 10); +/** + * IS `true` for Node.js 10.10 and greater. + */ +exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = MAJOR_VERSION > 10 || (MAJOR_VERSION === 10 && MINOR_VERSION >= 10); + + +/***/ }), +/* 640 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(641); +exports.fs = fs; + + +/***/ }), +/* 641 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +class DirentFromStats { + constructor(name, stats) { + this.name = name; + this.isBlockDevice = stats.isBlockDevice.bind(stats); + this.isCharacterDevice = stats.isCharacterDevice.bind(stats); + this.isDirectory = stats.isDirectory.bind(stats); + this.isFIFO = stats.isFIFO.bind(stats); + this.isFile = stats.isFile.bind(stats); + this.isSocket = stats.isSocket.bind(stats); + this.isSymbolicLink = stats.isSymbolicLink.bind(stats); + } +} +function createDirentFromStats(name, stats) { + return new DirentFromStats(name, stats); +} +exports.createDirentFromStats = createDirentFromStats; + + +/***/ }), +/* 642 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsStat = __webpack_require__(628); +const constants_1 = __webpack_require__(639); +const utils = __webpack_require__(640); +function read(dir, settings) { + if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { + return readdirWithFileTypes(dir, settings); + } + return readdir(dir, settings); +} +exports.read = read; +function readdirWithFileTypes(dir, settings) { + const dirents = settings.fs.readdirSync(dir, { withFileTypes: true }); + return dirents.map((dirent) => { + const entry = { + dirent, + name: dirent.name, + path: `${dir}${settings.pathSegmentSeparator}${dirent.name}` + }; + if (entry.dirent.isSymbolicLink() && settings.followSymbolicLinks) { + try { + const stats = settings.fs.statSync(entry.path); + entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); + } + catch (error) { + if (settings.throwErrorOnBrokenSymbolicLink) { + throw error; + } + } + } + return entry; + }); +} +exports.readdirWithFileTypes = readdirWithFileTypes; +function readdir(dir, settings) { + const names = settings.fs.readdirSync(dir); + return names.map((name) => { + const entryPath = `${dir}${settings.pathSegmentSeparator}${name}`; + const stats = fsStat.statSync(entryPath, settings.fsStatSettings); + const entry = { + name, + path: entryPath, + dirent: utils.fs.createDirentFromStats(name, stats) + }; + if (settings.stats) { + entry.stats = stats; + } + return entry; + }); +} +exports.readdir = readdir; + + +/***/ }), +/* 643 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(16); +const fsStat = __webpack_require__(628); +const fs = __webpack_require__(644); +class Settings { + constructor(_options = {}) { + this._options = _options; + this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, false); + this.fs = fs.createFileSystemAdapter(this._options.fs); + this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); + this.stats = this._getValue(this._options.stats, false); + this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); + this.fsStatSettings = new fsStat.Settings({ + followSymbolicLink: this.followSymbolicLinks, + fs: this.fs, + throwErrorOnBrokenSymbolicLink: this.throwErrorOnBrokenSymbolicLink + }); + } + _getValue(option, value) { + return option === undefined ? value : option; + } +} +exports.default = Settings; + + +/***/ }), +/* 644 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(23); +exports.FILE_SYSTEM_ADAPTER = { + lstat: fs.lstat, + stat: fs.stat, + lstatSync: fs.lstatSync, + statSync: fs.statSync, + readdir: fs.readdir, + readdirSync: fs.readdirSync +}; +function createFileSystemAdapter(fsMethods) { + if (!fsMethods) { + return exports.FILE_SYSTEM_ADAPTER; + } + return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); +} +exports.createFileSystemAdapter = createFileSystemAdapter; + + +/***/ }), +/* 645 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var reusify = __webpack_require__(646) + +function fastqueue (context, worker, concurrency) { + if (typeof context === 'function') { + concurrency = worker + worker = context + context = null + } + + var cache = reusify(Task) + var queueHead = null + var queueTail = null + var _running = 0 + + var self = { + push: push, + drain: noop, + saturated: noop, + pause: pause, + paused: false, + concurrency: concurrency, + running: running, + resume: resume, + idle: idle, + length: length, + unshift: unshift, + empty: noop, + kill: kill, + killAndDrain: killAndDrain + } + + return self + + function running () { + return _running + } + + function pause () { + self.paused = true + } + + function length () { + var current = queueHead + var counter = 0 + + while (current) { + current = current.next + counter++ + } + + return counter + } + + function resume () { + if (!self.paused) return + self.paused = false + for (var i = 0; i < self.concurrency; i++) { + _running++ + release() + } + } + + function idle () { + return _running === 0 && self.length() === 0 + } + + function push (value, done) { + var current = cache.get() + + current.context = context + current.release = release + current.value = value + current.callback = done || noop + + if (_running === self.concurrency || self.paused) { + if (queueTail) { + queueTail.next = current + queueTail = current + } else { + queueHead = current + queueTail = current + self.saturated() + } + } else { + _running++ + worker.call(context, current.value, current.worked) + } + } + + function unshift (value, done) { + var current = cache.get() + + current.context = context + current.release = release + current.value = value + current.callback = done || noop + + if (_running === self.concurrency || self.paused) { + if (queueHead) { + current.next = queueHead + queueHead = current + } else { + queueHead = current + queueTail = current + self.saturated() + } + } else { + _running++ + worker.call(context, current.value, current.worked) + } + } + + function release (holder) { + if (holder) { + cache.release(holder) + } + var next = queueHead + if (next) { + if (!self.paused) { + if (queueTail === queueHead) { + queueTail = null + } + queueHead = next.next + next.next = null + worker.call(context, next.value, next.worked) + if (queueTail === null) { + self.empty() + } + } else { + _running-- + } + } else if (--_running === 0) { + self.drain() + } + } + + function kill () { + queueHead = null + queueTail = null + self.drain = noop + } + + function killAndDrain () { + queueHead = null + queueTail = null + self.drain() + self.drain = noop + } +} + +function noop () {} + +function Task () { + this.value = null + this.callback = noop + this.next = null + this.release = noop + this.context = null + + var self = this + + this.worked = function worked (err, result) { + var callback = self.callback + self.value = null + self.callback = noop + callback.call(self.context, err, result) + self.release(self) + } +} + +module.exports = fastqueue + + +/***/ }), +/* 646 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +function reusify (Constructor) { + var head = new Constructor() + var tail = head + + function get () { + var current = head + + if (current.next) { + head = current.next + } else { + head = new Constructor() + tail = head + } + + current.next = null + + return current + } + + function release (obj) { + tail.next = obj + tail = obj + } + + return { + get: get, + release: release + } +} + +module.exports = reusify + + +/***/ }), +/* 647 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function isFatalError(settings, error) { + if (settings.errorFilter === null) { + return true; + } + return !settings.errorFilter(error); +} +exports.isFatalError = isFatalError; +function isAppliedFilter(filter, value) { + return filter === null || filter(value); +} +exports.isAppliedFilter = isAppliedFilter; +function replacePathSegmentSeparator(filepath, separator) { + return filepath.split(/[\\\/]/).join(separator); +} +exports.replacePathSegmentSeparator = replacePathSegmentSeparator; +function joinPathSegments(a, b, separator) { + if (a === '') { + return b; + } + return a + separator + b; +} +exports.joinPathSegments = joinPathSegments; + + +/***/ }), +/* 648 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const common = __webpack_require__(647); +class Reader { + constructor(_root, _settings) { + this._root = _root; + this._settings = _settings; + this._root = common.replacePathSegmentSeparator(_root, _settings.pathSegmentSeparator); + } +} +exports.default = Reader; + + +/***/ }), +/* 649 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const stream_1 = __webpack_require__(27); +const async_1 = __webpack_require__(635); +class StreamProvider { + constructor(_root, _settings) { + this._root = _root; + this._settings = _settings; + this._reader = new async_1.default(this._root, this._settings); + this._stream = new stream_1.Readable({ + objectMode: true, + read: () => { }, + destroy: this._reader.destroy.bind(this._reader) + }); + } + read() { + this._reader.onError((error) => { + this._stream.emit('error', error); + }); + this._reader.onEntry((entry) => { + this._stream.push(entry); + }); + this._reader.onEnd(() => { + this._stream.push(null); + }); + this._reader.read(); + return this._stream; + } +} +exports.default = StreamProvider; + + +/***/ }), +/* 650 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const sync_1 = __webpack_require__(651); +class SyncProvider { + constructor(_root, _settings) { + this._root = _root; + this._settings = _settings; + this._reader = new sync_1.default(this._root, this._settings); + } + read() { + return this._reader.read(); + } +} +exports.default = SyncProvider; + + +/***/ }), +/* 651 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsScandir = __webpack_require__(636); +const common = __webpack_require__(647); +const reader_1 = __webpack_require__(648); +class SyncReader extends reader_1.default { + constructor() { + super(...arguments); + this._scandir = fsScandir.scandirSync; + this._storage = new Set(); + this._queue = new Set(); + } + read() { + this._pushToQueue(this._root, this._settings.basePath); + this._handleQueue(); + return Array.from(this._storage); + } + _pushToQueue(dir, base) { + this._queue.add({ dir, base }); + } + _handleQueue() { + for (const item of this._queue.values()) { + this._handleDirectory(item.dir, item.base); + } + } + _handleDirectory(dir, base) { + try { + const entries = this._scandir(dir, this._settings.fsScandirSettings); + for (const entry of entries) { + this._handleEntry(entry, base); + } + } + catch (error) { + this._handleError(error); + } + } + _handleError(error) { + if (!common.isFatalError(this._settings, error)) { + return; + } + throw error; + } + _handleEntry(entry, base) { + const fullpath = entry.path; + if (base !== undefined) { + entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); + } + if (common.isAppliedFilter(this._settings.entryFilter, entry)) { + this._pushToStorage(entry); + } + if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { + this._pushToQueue(fullpath, entry.path); + } + } + _pushToStorage(entry) { + this._storage.add(entry); + } +} +exports.default = SyncReader; + + +/***/ }), +/* 652 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(16); +const fsScandir = __webpack_require__(636); +class Settings { + constructor(_options = {}) { + this._options = _options; + this.basePath = this._getValue(this._options.basePath, undefined); + this.concurrency = this._getValue(this._options.concurrency, Infinity); + this.deepFilter = this._getValue(this._options.deepFilter, null); + this.entryFilter = this._getValue(this._options.entryFilter, null); + this.errorFilter = this._getValue(this._options.errorFilter, null); + this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); + this.fsScandirSettings = new fsScandir.Settings({ + followSymbolicLinks: this._options.followSymbolicLinks, + fs: this._options.fs, + pathSegmentSeparator: this._options.pathSegmentSeparator, + stats: this._options.stats, + throwErrorOnBrokenSymbolicLink: this._options.throwErrorOnBrokenSymbolicLink + }); + } + _getValue(option, value) { + return option === undefined ? value : option; + } +} +exports.default = Settings; + + +/***/ }), /* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(594); +const path = __webpack_require__(16); +const fsStat = __webpack_require__(628); +const utils = __webpack_require__(599); +class Reader { + constructor(_settings) { + this._settings = _settings; + this._fsStatSettings = new fsStat.Settings({ + followSymbolicLink: this._settings.followSymbolicLinks, + fs: this._settings.fs, + throwErrorOnBrokenSymbolicLink: this._settings.followSymbolicLinks + }); + } + _getFullEntryPath(filepath) { + return path.resolve(this._settings.cwd, filepath); + } + _makeEntry(stats, pattern) { + const entry = { + name: pattern, + path: pattern, + dirent: utils.fs.createDirentFromStats(pattern, stats) + }; + if (this._settings.stats) { + entry.stats = stats; + } + return entry; + } + _isFatalError(error) { + return !utils.errno.isEnoentCodeError(error) && !this._settings.suppressErrors; + } +} +exports.default = Reader; + + +/***/ }), +/* 654 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(16); +const deep_1 = __webpack_require__(655); +const entry_1 = __webpack_require__(656); +const error_1 = __webpack_require__(657); +const entry_2 = __webpack_require__(658); +class Provider { + constructor(_settings) { + this._settings = _settings; + this.errorFilter = new error_1.default(this._settings); + this.entryFilter = new entry_1.default(this._settings, this._getMicromatchOptions()); + this.deepFilter = new deep_1.default(this._settings, this._getMicromatchOptions()); + this.entryTransformer = new entry_2.default(this._settings); + } + _getRootDirectory(task) { + return path.resolve(this._settings.cwd, task.base); + } + _getReaderOptions(task) { + const basePath = task.base === '.' ? '' : task.base; + return { + basePath, + pathSegmentSeparator: '/', + concurrency: this._settings.concurrency, + deepFilter: this.deepFilter.getFilter(basePath, task.positive, task.negative), + entryFilter: this.entryFilter.getFilter(task.positive, task.negative), + errorFilter: this.errorFilter.getFilter(), + followSymbolicLinks: this._settings.followSymbolicLinks, + fs: this._settings.fs, + stats: this._settings.stats, + throwErrorOnBrokenSymbolicLink: this._settings.throwErrorOnBrokenSymbolicLink, + transform: this.entryTransformer.getTransformer() + }; + } + _getMicromatchOptions() { + return { + dot: this._settings.dot, + matchBase: this._settings.baseNameMatch, + nobrace: !this._settings.braceExpansion, + nocase: !this._settings.caseSensitiveMatch, + noext: !this._settings.extglob, + noglobstar: !this._settings.globstar, + posix: true, + strictSlashes: false + }; + } +} +exports.default = Provider; + + +/***/ }), +/* 655 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(599); +class DeepFilter { + constructor(_settings, _micromatchOptions) { + this._settings = _settings; + this._micromatchOptions = _micromatchOptions; + } + getFilter(basePath, positive, negative) { + const maxPatternDepth = this._getMaxPatternDepth(positive); + const negativeRe = this._getNegativePatternsRe(negative); + return (entry) => this._filter(basePath, entry, negativeRe, maxPatternDepth); + } + _getMaxPatternDepth(patterns) { + const globstar = patterns.some(utils.pattern.hasGlobStar); + return globstar ? Infinity : utils.pattern.getMaxNaivePatternsDepth(patterns); + } + _getNegativePatternsRe(patterns) { + const affectDepthOfReadingPatterns = patterns.filter(utils.pattern.isAffectDepthOfReadingPattern); + return utils.pattern.convertPatternsToRe(affectDepthOfReadingPatterns, this._micromatchOptions); + } + _filter(basePath, entry, negativeRe, maxPatternDepth) { + const depth = this._getEntryDepth(basePath, entry.path); + if (this._isSkippedByDeep(depth)) { + return false; + } + if (this._isSkippedByMaxPatternDepth(depth, maxPatternDepth)) { + return false; + } + if (this._isSkippedSymbolicLink(entry)) { + return false; + } + if (this._isSkippedDotDirectory(entry)) { + return false; + } + return this._isSkippedByNegativePatterns(entry, negativeRe); + } + _getEntryDepth(basePath, entryPath) { + const basePathDepth = basePath.split('/').length; + const entryPathDepth = entryPath.split('/').length; + return entryPathDepth - (basePath === '' ? 0 : basePathDepth); + } + _isSkippedByDeep(entryDepth) { + return entryDepth >= this._settings.deep; + } + _isSkippedByMaxPatternDepth(entryDepth, maxPatternDepth) { + return !this._settings.baseNameMatch && maxPatternDepth !== Infinity && entryDepth > maxPatternDepth; + } + _isSkippedSymbolicLink(entry) { + return !this._settings.followSymbolicLinks && entry.dirent.isSymbolicLink(); + } + _isSkippedDotDirectory(entry) { + return !this._settings.dot && entry.name.startsWith('.'); + } + _isSkippedByNegativePatterns(entry, negativeRe) { + return !utils.pattern.matchAny(entry.path, negativeRe); + } +} +exports.default = DeepFilter; + + +/***/ }), +/* 656 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(599); +class EntryFilter { + constructor(_settings, _micromatchOptions) { + this._settings = _settings; + this._micromatchOptions = _micromatchOptions; + this.index = new Map(); + } + getFilter(positive, negative) { + const positiveRe = utils.pattern.convertPatternsToRe(positive, this._micromatchOptions); + const negativeRe = utils.pattern.convertPatternsToRe(negative, this._micromatchOptions); + return (entry) => this._filter(entry, positiveRe, negativeRe); + } + _filter(entry, positiveRe, negativeRe) { + if (this._settings.unique) { + if (this._isDuplicateEntry(entry)) { + return false; + } + this._createIndexRecord(entry); + } + if (this._onlyFileFilter(entry) || this._onlyDirectoryFilter(entry)) { + return false; + } + if (this._isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { + return false; + } + const filepath = this._settings.baseNameMatch ? entry.name : entry.path; + return this._isMatchToPatterns(filepath, positiveRe) && !this._isMatchToPatterns(entry.path, negativeRe); + } + _isDuplicateEntry(entry) { + return this.index.has(entry.path); + } + _createIndexRecord(entry) { + this.index.set(entry.path, undefined); + } + _onlyFileFilter(entry) { + return this._settings.onlyFiles && !entry.dirent.isFile(); + } + _onlyDirectoryFilter(entry) { + return this._settings.onlyDirectories && !entry.dirent.isDirectory(); + } + _isSkippedByAbsoluteNegativePatterns(entry, negativeRe) { + if (!this._settings.absolute) { + return false; + } + const fullpath = utils.path.makeAbsolute(this._settings.cwd, entry.path); + return this._isMatchToPatterns(fullpath, negativeRe); + } + _isMatchToPatterns(filepath, patternsRe) { + return utils.pattern.matchAny(filepath, patternsRe); + } +} +exports.default = EntryFilter; + + +/***/ }), +/* 657 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(599); +class ErrorFilter { + constructor(_settings) { + this._settings = _settings; + } + getFilter() { + return (error) => this._isNonFatalError(error); + } + _isNonFatalError(error) { + return utils.errno.isEnoentCodeError(error) || this._settings.suppressErrors; + } +} +exports.default = ErrorFilter; + + +/***/ }), +/* 658 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(599); class EntryTransformer { constructor(_settings) { this._settings = _settings; @@ -75236,2515 +76839,3068 @@ exports.default = EntryTransformer; /***/ }), -/* 654 */ +/* 659 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const stream_1 = __webpack_require__(27); +const stream_2 = __webpack_require__(627); +const provider_1 = __webpack_require__(654); +class ProviderStream extends provider_1.default { + constructor() { + super(...arguments); + this._reader = new stream_2.default(this._settings); + } + read(task) { + const root = this._getRootDirectory(task); + const options = this._getReaderOptions(task); + const source = this.api(root, task, options); + const dest = new stream_1.Readable({ objectMode: true, read: () => { } }); + source + .once('error', (error) => dest.emit('error', error)) + .on('data', (entry) => dest.emit('data', options.transform(entry))) + .once('end', () => dest.emit('end')); + return dest; + } + api(root, task, options) { + if (task.dynamic) { + return this._reader.dynamic(root, options); + } + return this._reader.static(task.patterns, options); + } +} +exports.default = ProviderStream; + + +/***/ }), +/* 660 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const sync_1 = __webpack_require__(661); +const provider_1 = __webpack_require__(654); +class ProviderSync extends provider_1.default { + constructor() { + super(...arguments); + this._reader = new sync_1.default(this._settings); + } + read(task) { + const root = this._getRootDirectory(task); + const options = this._getReaderOptions(task); + const entries = this.api(root, task, options); + return entries.map(options.transform); + } + api(root, task, options) { + if (task.dynamic) { + return this._reader.dynamic(root, options); + } + return this._reader.static(task.patterns, options); + } +} +exports.default = ProviderSync; + + +/***/ }), +/* 661 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsStat = __webpack_require__(628); +const fsWalk = __webpack_require__(633); +const reader_1 = __webpack_require__(653); +class ReaderSync extends reader_1.default { + constructor() { + super(...arguments); + this._walkSync = fsWalk.walkSync; + this._statSync = fsStat.statSync; + } + dynamic(root, options) { + return this._walkSync(root, options); + } + static(patterns, options) { + const entries = []; + for (const pattern of patterns) { + const filepath = this._getFullEntryPath(pattern); + const entry = this._getEntry(filepath, pattern, options); + if (entry === null || !options.entryFilter(entry)) { + continue; + } + entries.push(entry); + } + return entries; + } + _getEntry(filepath, pattern, options) { + try { + const stats = this._getStat(filepath); + return this._makeEntry(stats, pattern); + } + catch (error) { + if (options.errorFilter(error)) { + return null; + } + throw error; + } + } + _getStat(filepath) { + return this._statSync(filepath, this._fsStatSettings); + } +} +exports.default = ReaderSync; + + +/***/ }), +/* 662 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(23); +const os = __webpack_require__(11); +const CPU_COUNT = os.cpus().length; +exports.DEFAULT_FILE_SYSTEM_ADAPTER = { + lstat: fs.lstat, + lstatSync: fs.lstatSync, + stat: fs.stat, + statSync: fs.statSync, + readdir: fs.readdir, + readdirSync: fs.readdirSync +}; +// tslint:enable no-redundant-jsdoc +class Settings { + constructor(_options = {}) { + this._options = _options; + this.absolute = this._getValue(this._options.absolute, false); + this.baseNameMatch = this._getValue(this._options.baseNameMatch, false); + this.braceExpansion = this._getValue(this._options.braceExpansion, true); + this.caseSensitiveMatch = this._getValue(this._options.caseSensitiveMatch, true); + this.concurrency = this._getValue(this._options.concurrency, CPU_COUNT); + this.cwd = this._getValue(this._options.cwd, process.cwd()); + this.deep = this._getValue(this._options.deep, Infinity); + this.dot = this._getValue(this._options.dot, false); + this.extglob = this._getValue(this._options.extglob, true); + this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, true); + this.fs = this._getFileSystemMethods(this._options.fs); + this.globstar = this._getValue(this._options.globstar, true); + this.ignore = this._getValue(this._options.ignore, []); + this.markDirectories = this._getValue(this._options.markDirectories, false); + this.objectMode = this._getValue(this._options.objectMode, false); + this.onlyDirectories = this._getValue(this._options.onlyDirectories, false); + this.onlyFiles = this._getValue(this._options.onlyFiles, true); + this.stats = this._getValue(this._options.stats, false); + this.suppressErrors = this._getValue(this._options.suppressErrors, false); + this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, false); + this.unique = this._getValue(this._options.unique, true); + if (this.onlyDirectories) { + this.onlyFiles = false; + } + if (this.stats) { + this.objectMode = true; + } + } + _getValue(option, value) { + return option === undefined ? value : option; + } + _getFileSystemMethods(methods = {}) { + return Object.assign({}, exports.DEFAULT_FILE_SYSTEM_ADAPTER, methods); + } +} +exports.default = Settings; + + +/***/ }), +/* 663 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const path = __webpack_require__(16); +const pathType = __webpack_require__(664); + +const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; + +const getPath = (filepath, cwd) => { + const pth = filepath[0] === '!' ? filepath.slice(1) : filepath; + return path.isAbsolute(pth) ? pth : path.join(cwd, pth); +}; + +const addExtensions = (file, extensions) => { + if (path.extname(file)) { + return `**/${file}`; + } + + return `**/${file}.${getExtensions(extensions)}`; +}; + +const getGlob = (directory, options) => { + if (options.files && !Array.isArray(options.files)) { + throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof options.files}\``); + } + + if (options.extensions && !Array.isArray(options.extensions)) { + throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof options.extensions}\``); + } + + if (options.files && options.extensions) { + return options.files.map(x => path.posix.join(directory, addExtensions(x, options.extensions))); + } + + if (options.files) { + return options.files.map(x => path.posix.join(directory, `**/${x}`)); + } + + if (options.extensions) { + return [path.posix.join(directory, `**/*.${getExtensions(options.extensions)}`)]; + } + + return [path.posix.join(directory, '**')]; +}; + +module.exports = async (input, options) => { + options = { + cwd: process.cwd(), + ...options + }; + + if (typeof options.cwd !== 'string') { + throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); + } + + const globs = await Promise.all([].concat(input).map(async x => { + const isDirectory = await pathType.isDirectory(getPath(x, options.cwd)); + return isDirectory ? getGlob(x, options) : x; + })); + + return [].concat.apply([], globs); // eslint-disable-line prefer-spread +}; + +module.exports.sync = (input, options) => { + options = { + cwd: process.cwd(), + ...options + }; + + if (typeof options.cwd !== 'string') { + throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); + } + + const globs = [].concat(input).map(x => pathType.isDirectorySync(getPath(x, options.cwd)) ? getGlob(x, options) : x); + + return [].concat.apply([], globs); // eslint-disable-line prefer-spread +}; + + +/***/ }), +/* 664 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const {promisify} = __webpack_require__(29); +const fs = __webpack_require__(23); + +async function isType(fsStatType, statsMethodName, filePath) { + if (typeof filePath !== 'string') { + throw new TypeError(`Expected a string, got ${typeof filePath}`); + } + + try { + const stats = await promisify(fs[fsStatType])(filePath); + return stats[statsMethodName](); + } catch (error) { + if (error.code === 'ENOENT') { + return false; + } + + throw error; + } +} + +function isTypeSync(fsStatType, statsMethodName, filePath) { + if (typeof filePath !== 'string') { + throw new TypeError(`Expected a string, got ${typeof filePath}`); + } + + try { + return fs[fsStatType](filePath)[statsMethodName](); + } catch (error) { + if (error.code === 'ENOENT') { + return false; + } + + throw error; + } +} + +exports.isFile = isType.bind(null, 'stat', 'isFile'); +exports.isDirectory = isType.bind(null, 'stat', 'isDirectory'); +exports.isSymlink = isType.bind(null, 'lstat', 'isSymbolicLink'); +exports.isFileSync = isTypeSync.bind(null, 'statSync', 'isFile'); +exports.isDirectorySync = isTypeSync.bind(null, 'statSync', 'isDirectory'); +exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); + + +/***/ }), +/* 665 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(27); -const stream_2 = __webpack_require__(622); -const provider_1 = __webpack_require__(649); -class ProviderStream extends provider_1.default { - constructor() { - super(...arguments); - this._reader = new stream_2.default(this._settings); - } - read(task) { - const root = this._getRootDirectory(task); - const options = this._getReaderOptions(task); - const source = this.api(root, task, options); - const dest = new stream_1.Readable({ objectMode: true, read: () => { } }); - source - .once('error', (error) => dest.emit('error', error)) - .on('data', (entry) => dest.emit('data', options.transform(entry))) - .once('end', () => dest.emit('end')); - return dest; - } - api(root, task, options) { - if (task.dynamic) { - return this._reader.dynamic(root, options); - } - return this._reader.static(task.patterns, options); - } -} -exports.default = ProviderStream; + +const {promisify} = __webpack_require__(29); +const fs = __webpack_require__(23); +const path = __webpack_require__(16); +const fastGlob = __webpack_require__(597); +const gitIgnore = __webpack_require__(666); +const slash = __webpack_require__(667); + +const DEFAULT_IGNORE = [ + '**/node_modules/**', + '**/flow-typed/**', + '**/coverage/**', + '**/.git' +]; + +const readFileP = promisify(fs.readFile); + +const mapGitIgnorePatternTo = base => ignore => { + if (ignore.startsWith('!')) { + return '!' + path.posix.join(base, ignore.slice(1)); + } + + return path.posix.join(base, ignore); +}; + +const parseGitIgnore = (content, options) => { + const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); + + return content + .split(/\r?\n/) + .filter(Boolean) + .filter(line => !line.startsWith('#')) + .map(mapGitIgnorePatternTo(base)); +}; + +const reduceIgnore = files => { + return files.reduce((ignores, file) => { + ignores.add(parseGitIgnore(file.content, { + cwd: file.cwd, + fileName: file.filePath + })); + return ignores; + }, gitIgnore()); +}; + +const ensureAbsolutePathForCwd = (cwd, p) => { + if (path.isAbsolute(p)) { + if (p.startsWith(cwd)) { + return p; + } + + throw new Error(`Path ${p} is not in cwd ${cwd}`); + } + + return path.join(cwd, p); +}; + +const getIsIgnoredPredecate = (ignores, cwd) => { + return p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, p)))); +}; + +const getFile = async (file, cwd) => { + const filePath = path.join(cwd, file); + const content = await readFileP(filePath, 'utf8'); + + return { + cwd, + filePath, + content + }; +}; + +const getFileSync = (file, cwd) => { + const filePath = path.join(cwd, file); + const content = fs.readFileSync(filePath, 'utf8'); + + return { + cwd, + filePath, + content + }; +}; + +const normalizeOptions = ({ + ignore = [], + cwd = process.cwd() +} = {}) => { + return {ignore, cwd}; +}; + +module.exports = async options => { + options = normalizeOptions(options); + + const paths = await fastGlob('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }); + + const files = await Promise.all(paths.map(file => getFile(file, options.cwd))); + const ignores = reduceIgnore(files); + + return getIsIgnoredPredecate(ignores, options.cwd); +}; + +module.exports.sync = options => { + options = normalizeOptions(options); + + const paths = fastGlob.sync('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }); + + const files = paths.map(file => getFileSync(file, options.cwd)); + const ignores = reduceIgnore(files); + + return getIsIgnoredPredecate(ignores, options.cwd); +}; /***/ }), -/* 655 */ -/***/ (function(module, exports, __webpack_require__) { +/* 666 */ +/***/ (function(module, exports) { -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(656); -const provider_1 = __webpack_require__(649); -class ProviderSync extends provider_1.default { - constructor() { - super(...arguments); - this._reader = new sync_1.default(this._settings); - } - read(task) { - const root = this._getRootDirectory(task); - const options = this._getReaderOptions(task); - const entries = this.api(root, task, options); - return entries.map(options.transform); - } - api(root, task, options) { - if (task.dynamic) { - return this._reader.dynamic(root, options); - } - return this._reader.static(task.patterns, options); - } -} -exports.default = ProviderSync; +// A simple implementation of make-array +function makeArray (subject) { + return Array.isArray(subject) + ? subject + : [subject] +} + +const REGEX_TEST_BLANK_LINE = /^\s+$/ +const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/ +const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/ +const REGEX_SPLITALL_CRLF = /\r?\n/g +// /foo, +// ./foo, +// ../foo, +// . +// .. +const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/ + +const SLASH = '/' +const KEY_IGNORE = typeof Symbol !== 'undefined' + ? Symbol.for('node-ignore') + /* istanbul ignore next */ + : 'node-ignore' + +const define = (object, key, value) => + Object.defineProperty(object, key, {value}) + +const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g + +// Sanitize the range of a regular expression +// The cases are complicated, see test cases for details +const sanitizeRange = range => range.replace( + REGEX_REGEXP_RANGE, + (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) + ? match + // Invalid range (out of order) which is ok for gitignore rules but + // fatal for JavaScript regular expression, so eliminate it. + : '' +) + +// > If the pattern ends with a slash, +// > it is removed for the purpose of the following description, +// > but it would only find a match with a directory. +// > In other words, foo/ will match a directory foo and paths underneath it, +// > but will not match a regular file or a symbolic link foo +// > (this is consistent with the way how pathspec works in general in Git). +// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`' +// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call +// you could use option `mark: true` with `glob` + +// '`foo/`' should not continue with the '`..`' +const DEFAULT_REPLACER_PREFIX = [ + + // > Trailing spaces are ignored unless they are quoted with backslash ("\") + [ + // (a\ ) -> (a ) + // (a ) -> (a) + // (a \ ) -> (a ) + /\\?\s+$/, + match => match.indexOf('\\') === 0 + ? ' ' + : '' + ], + + // replace (\ ) with ' ' + [ + /\\\s/g, + () => ' ' + ], + + // Escape metacharacters + // which is written down by users but means special for regular expressions. + + // > There are 12 characters with special meanings: + // > - the backslash \, + // > - the caret ^, + // > - the dollar sign $, + // > - the period or dot ., + // > - the vertical bar or pipe symbol |, + // > - the question mark ?, + // > - the asterisk or star *, + // > - the plus sign +, + // > - the opening parenthesis (, + // > - the closing parenthesis ), + // > - and the opening square bracket [, + // > - the opening curly brace {, + // > These special characters are often called "metacharacters". + [ + /[\\^$.|*+(){]/g, + match => `\\${match}` + ], + + [ + // > [abc] matches any character inside the brackets + // > (in this case a, b, or c); + /\[([^\]/]*)($|\])/g, + (match, p1, p2) => p2 === ']' + ? `[${sanitizeRange(p1)}]` + : `\\${match}` + ], + + [ + // > a question mark (?) matches a single character + /(?!\\)\?/g, + () => '[^/]' + ], + + // leading slash + [ + + // > A leading slash matches the beginning of the pathname. + // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". + // A leading slash matches the beginning of the pathname + /^\//, + () => '^' + ], + + // replace special metacharacter slash after the leading slash + [ + /\//g, + () => '\\/' + ], + + [ + // > A leading "**" followed by a slash means match in all directories. + // > For example, "**/foo" matches file or directory "foo" anywhere, + // > the same as pattern "foo". + // > "**/foo/bar" matches file or directory "bar" anywhere that is directly + // > under directory "foo". + // Notice that the '*'s have been replaced as '\\*' + /^\^*\\\*\\\*\\\//, + + // '**/foo' <-> 'foo' + () => '^(?:.*\\/)?' + ] +] + +const DEFAULT_REPLACER_SUFFIX = [ + // starting + [ + // there will be no leading '/' + // (which has been replaced by section "leading slash") + // If starts with '**', adding a '^' to the regular expression also works + /^(?=[^^])/, + function startingReplacer () { + return !/\/(?!$)/.test(this) + // > If the pattern does not contain a slash /, + // > Git treats it as a shell glob pattern + // Actually, if there is only a trailing slash, + // git also treats it as a shell glob pattern + ? '(?:^|\\/)' + + // > Otherwise, Git treats the pattern as a shell glob suitable for + // > consumption by fnmatch(3) + : '^' + } + ], + + // two globstars + [ + // Use lookahead assertions so that we could match more than one `'/**'` + /\\\/\\\*\\\*(?=\\\/|$)/g, + + // Zero, one or several directories + // should not use '*', or it will be replaced by the next replacer + + // Check if it is not the last `'/**'` + (_, index, str) => index + 6 < str.length + + // case: /**/ + // > A slash followed by two consecutive asterisks then a slash matches + // > zero or more directories. + // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on. + // '/**/' + ? '(?:\\/[^\\/]+)*' + + // case: /** + // > A trailing `"/**"` matches everything inside. + + // #21: everything inside but it should not include the current folder + : '\\/.+' + ], + + // intermediate wildcards + [ + // Never replace escaped '*' + // ignore rule '\*' will match the path '*' + + // 'abc.*/' -> go + // 'abc.*' -> skip this rule + /(^|[^\\]+)\\\*(?=.+)/g, + + // '*.js' matches '.js' + // '*.js' doesn't match 'abc' + (_, p1) => `${p1}[^\\/]*` + ], + + // trailing wildcard + [ + /(\^|\\\/)?\\\*$/, + (_, p1) => { + const prefix = p1 + // '\^': + // '/*' does not match '' + // '/*' does not match everything + + // '\\\/': + // 'abc/*' does not match 'abc/' + ? `${p1}[^/]+` + + // 'a*' matches 'a' + // 'a*' matches 'aa' + : '[^/]*' + + return `${prefix}(?=$|\\/$)` + } + ], + + [ + // unescape + /\\\\\\/g, + () => '\\' + ] +] + +const POSITIVE_REPLACERS = [ + ...DEFAULT_REPLACER_PREFIX, + + // 'f' + // matches + // - /f(end) + // - /f/ + // - (start)f(end) + // - (start)f/ + // doesn't match + // - oof + // - foo + // pseudo: + // -> (^|/)f(/|$) + + // ending + [ + // 'js' will not match 'js.' + // 'ab' will not match 'abc' + /(?:[^*/])$/, + + // 'js*' will not match 'a.js' + // 'js/' will not match 'a.js' + // 'js' will match 'a.js' and 'a.js/' + match => `${match}(?=$|\\/)` + ], + + ...DEFAULT_REPLACER_SUFFIX +] + +const NEGATIVE_REPLACERS = [ + ...DEFAULT_REPLACER_PREFIX, + + // #24, #38 + // The MISSING rule of [gitignore docs](https://git-scm.com/docs/gitignore) + // A negative pattern without a trailing wildcard should not + // re-include the things inside that directory. + + // eg: + // ['node_modules/*', '!node_modules'] + // should ignore `node_modules/a.js` + [ + /(?:[^*])$/, + match => `${match}(?=$|\\/$)` + ], + + ...DEFAULT_REPLACER_SUFFIX +] + +// A simple cache, because an ignore rule only has only one certain meaning +const regexCache = Object.create(null) + +// @param {pattern} +const makeRegex = (pattern, negative, ignorecase) => { + const r = regexCache[pattern] + if (r) { + return r + } + + const replacers = negative + ? NEGATIVE_REPLACERS + : POSITIVE_REPLACERS + + const source = replacers.reduce( + (prev, current) => prev.replace(current[0], current[1].bind(pattern)), + pattern + ) + + return regexCache[pattern] = ignorecase + ? new RegExp(source, 'i') + : new RegExp(source) +} + +const isString = subject => typeof subject === 'string' + +// > A blank line matches no files, so it can serve as a separator for readability. +const checkPattern = pattern => pattern + && isString(pattern) + && !REGEX_TEST_BLANK_LINE.test(pattern) + + // > A line starting with # serves as a comment. + && pattern.indexOf('#') !== 0 + +const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF) + +class IgnoreRule { + constructor ( + origin, + pattern, + negative, + regex + ) { + this.origin = origin + this.pattern = pattern + this.negative = negative + this.regex = regex + } +} + +const createRule = (pattern, ignorecase) => { + const origin = pattern + let negative = false + + // > An optional prefix "!" which negates the pattern; + if (pattern.indexOf('!') === 0) { + negative = true + pattern = pattern.substr(1) + } + pattern = pattern + // > Put a backslash ("\") in front of the first "!" for patterns that + // > begin with a literal "!", for example, `"\!important!.txt"`. + .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!') + // > Put a backslash ("\") in front of the first hash for patterns that + // > begin with a hash. + .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#') -/***/ }), -/* 656 */ -/***/ (function(module, exports, __webpack_require__) { + const regex = makeRegex(pattern, negative, ignorecase) -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(623); -const fsWalk = __webpack_require__(628); -const reader_1 = __webpack_require__(648); -class ReaderSync extends reader_1.default { - constructor() { - super(...arguments); - this._walkSync = fsWalk.walkSync; - this._statSync = fsStat.statSync; - } - dynamic(root, options) { - return this._walkSync(root, options); - } - static(patterns, options) { - const entries = []; - for (const pattern of patterns) { - const filepath = this._getFullEntryPath(pattern); - const entry = this._getEntry(filepath, pattern, options); - if (entry === null || !options.entryFilter(entry)) { - continue; - } - entries.push(entry); - } - return entries; - } - _getEntry(filepath, pattern, options) { - try { - const stats = this._getStat(filepath); - return this._makeEntry(stats, pattern); - } - catch (error) { - if (options.errorFilter(error)) { - return null; - } - throw error; - } - } - _getStat(filepath) { - return this._statSync(filepath, this._fsStatSettings); - } -} -exports.default = ReaderSync; + return new IgnoreRule( + origin, + pattern, + negative, + regex + ) +} +const throwError = (message, Ctor) => { + throw new Ctor(message) +} -/***/ }), -/* 657 */ -/***/ (function(module, exports, __webpack_require__) { +const checkPath = (path, originalPath, doThrow) => { + if (!isString(path)) { + return doThrow( + `path must be a string, but got \`${originalPath}\``, + TypeError + ) + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(23); -const os = __webpack_require__(11); -const CPU_COUNT = os.cpus().length; -exports.DEFAULT_FILE_SYSTEM_ADAPTER = { - lstat: fs.lstat, - lstatSync: fs.lstatSync, - stat: fs.stat, - statSync: fs.statSync, - readdir: fs.readdir, - readdirSync: fs.readdirSync -}; -// tslint:enable no-redundant-jsdoc -class Settings { - constructor(_options = {}) { - this._options = _options; - this.absolute = this._getValue(this._options.absolute, false); - this.baseNameMatch = this._getValue(this._options.baseNameMatch, false); - this.braceExpansion = this._getValue(this._options.braceExpansion, true); - this.caseSensitiveMatch = this._getValue(this._options.caseSensitiveMatch, true); - this.concurrency = this._getValue(this._options.concurrency, CPU_COUNT); - this.cwd = this._getValue(this._options.cwd, process.cwd()); - this.deep = this._getValue(this._options.deep, Infinity); - this.dot = this._getValue(this._options.dot, false); - this.extglob = this._getValue(this._options.extglob, true); - this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, true); - this.fs = this._getFileSystemMethods(this._options.fs); - this.globstar = this._getValue(this._options.globstar, true); - this.ignore = this._getValue(this._options.ignore, []); - this.markDirectories = this._getValue(this._options.markDirectories, false); - this.objectMode = this._getValue(this._options.objectMode, false); - this.onlyDirectories = this._getValue(this._options.onlyDirectories, false); - this.onlyFiles = this._getValue(this._options.onlyFiles, true); - this.stats = this._getValue(this._options.stats, false); - this.suppressErrors = this._getValue(this._options.suppressErrors, false); - this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, false); - this.unique = this._getValue(this._options.unique, true); - if (this.onlyDirectories) { - this.onlyFiles = false; - } - if (this.stats) { - this.objectMode = true; - } - } - _getValue(option, value) { - return option === undefined ? value : option; - } - _getFileSystemMethods(methods = {}) { - return Object.assign({}, exports.DEFAULT_FILE_SYSTEM_ADAPTER, methods); - } -} -exports.default = Settings; + // We don't know if we should ignore '', so throw + if (!path) { + return doThrow(`path must not be empty`, TypeError) + } + // Check if it is a relative path + if (checkPath.isNotRelative(path)) { + const r = '`path.relative()`d' + return doThrow( + `path should be a ${r} string, but got "${originalPath}"`, + RangeError + ) + } -/***/ }), -/* 658 */ -/***/ (function(module, exports, __webpack_require__) { + return true +} -"use strict"; +const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path) -const path = __webpack_require__(16); -const pathType = __webpack_require__(659); +checkPath.isNotRelative = isNotRelative +checkPath.convert = p => p -const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; +class Ignore { + constructor ({ + ignorecase = true + } = {}) { + this._rules = [] + this._ignorecase = ignorecase + define(this, KEY_IGNORE, true) + this._initCache() + } -const getPath = (filepath, cwd) => { - const pth = filepath[0] === '!' ? filepath.slice(1) : filepath; - return path.isAbsolute(pth) ? pth : path.join(cwd, pth); -}; + _initCache () { + this._ignoreCache = Object.create(null) + this._testCache = Object.create(null) + } -const addExtensions = (file, extensions) => { - if (path.extname(file)) { - return `**/${file}`; - } + _addPattern (pattern) { + // #32 + if (pattern && pattern[KEY_IGNORE]) { + this._rules = this._rules.concat(pattern._rules) + this._added = true + return + } - return `**/${file}.${getExtensions(extensions)}`; -}; + if (checkPattern(pattern)) { + const rule = createRule(pattern, this._ignorecase) + this._added = true + this._rules.push(rule) + } + } -const getGlob = (directory, options) => { - if (options.files && !Array.isArray(options.files)) { - throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof options.files}\``); - } + // @param {Array | string | Ignore} pattern + add (pattern) { + this._added = false - if (options.extensions && !Array.isArray(options.extensions)) { - throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof options.extensions}\``); - } + makeArray( + isString(pattern) + ? splitPattern(pattern) + : pattern + ).forEach(this._addPattern, this) - if (options.files && options.extensions) { - return options.files.map(x => path.posix.join(directory, addExtensions(x, options.extensions))); - } + // Some rules have just added to the ignore, + // making the behavior changed. + if (this._added) { + this._initCache() + } - if (options.files) { - return options.files.map(x => path.posix.join(directory, `**/${x}`)); - } + return this + } - if (options.extensions) { - return [path.posix.join(directory, `**/*.${getExtensions(options.extensions)}`)]; - } + // legacy + addPattern (pattern) { + return this.add(pattern) + } - return [path.posix.join(directory, '**')]; -}; + // | ignored : unignored + // negative | 0:0 | 0:1 | 1:0 | 1:1 + // -------- | ------- | ------- | ------- | -------- + // 0 | TEST | TEST | SKIP | X + // 1 | TESTIF | SKIP | TEST | X -module.exports = async (input, options) => { - options = { - cwd: process.cwd(), - ...options - }; + // - SKIP: always skip + // - TEST: always test + // - TESTIF: only test if checkUnignored + // - X: that never happen - if (typeof options.cwd !== 'string') { - throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); - } + // @param {boolean} whether should check if the path is unignored, + // setting `checkUnignored` to `false` could reduce additional + // path matching. - const globs = await Promise.all([].concat(input).map(async x => { - const isDirectory = await pathType.isDirectory(getPath(x, options.cwd)); - return isDirectory ? getGlob(x, options) : x; - })); + // @returns {TestResult} true if a file is ignored + _testOne (path, checkUnignored) { + let ignored = false + let unignored = false - return [].concat.apply([], globs); // eslint-disable-line prefer-spread -}; + this._rules.forEach(rule => { + const {negative} = rule + if ( + unignored === negative && ignored !== unignored + || negative && !ignored && !unignored && !checkUnignored + ) { + return + } -module.exports.sync = (input, options) => { - options = { - cwd: process.cwd(), - ...options - }; + const matched = rule.regex.test(path) - if (typeof options.cwd !== 'string') { - throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); - } + if (matched) { + ignored = !negative + unignored = negative + } + }) - const globs = [].concat(input).map(x => pathType.isDirectorySync(getPath(x, options.cwd)) ? getGlob(x, options) : x); + return { + ignored, + unignored + } + } - return [].concat.apply([], globs); // eslint-disable-line prefer-spread -}; + // @returns {TestResult} + _test (originalPath, cache, checkUnignored, slices) { + const path = originalPath + // Supports nullable path + && checkPath.convert(originalPath) + checkPath(path, originalPath, throwError) -/***/ }), -/* 659 */ -/***/ (function(module, exports, __webpack_require__) { + return this._t(path, cache, checkUnignored, slices) + } -"use strict"; + _t (path, cache, checkUnignored, slices) { + if (path in cache) { + return cache[path] + } -const {promisify} = __webpack_require__(29); -const fs = __webpack_require__(23); + if (!slices) { + // path/to/a.js + // ['path', 'to', 'a.js'] + slices = path.split(SLASH) + } -async function isType(fsStatType, statsMethodName, filePath) { - if (typeof filePath !== 'string') { - throw new TypeError(`Expected a string, got ${typeof filePath}`); - } + slices.pop() - try { - const stats = await promisify(fs[fsStatType])(filePath); - return stats[statsMethodName](); - } catch (error) { - if (error.code === 'ENOENT') { - return false; - } + // If the path has no parent directory, just test it + if (!slices.length) { + return cache[path] = this._testOne(path, checkUnignored) + } - throw error; - } -} + const parent = this._t( + slices.join(SLASH) + SLASH, + cache, + checkUnignored, + slices + ) -function isTypeSync(fsStatType, statsMethodName, filePath) { - if (typeof filePath !== 'string') { - throw new TypeError(`Expected a string, got ${typeof filePath}`); - } + // If the path contains a parent directory, check the parent first + return cache[path] = parent.ignored + // > It is not possible to re-include a file if a parent directory of + // > that file is excluded. + ? parent + : this._testOne(path, checkUnignored) + } - try { - return fs[fsStatType](filePath)[statsMethodName](); - } catch (error) { - if (error.code === 'ENOENT') { - return false; - } + ignores (path) { + return this._test(path, this._ignoreCache, false).ignored + } - throw error; - } + createFilter () { + return path => !this.ignores(path) + } + + filter (paths) { + return makeArray(paths).filter(this.createFilter()) + } + + // @returns {TestResult} + test (path) { + return this._test(path, this._testCache, true) + } } -exports.isFile = isType.bind(null, 'stat', 'isFile'); -exports.isDirectory = isType.bind(null, 'stat', 'isDirectory'); -exports.isSymlink = isType.bind(null, 'lstat', 'isSymbolicLink'); -exports.isFileSync = isTypeSync.bind(null, 'statSync', 'isFile'); -exports.isDirectorySync = isTypeSync.bind(null, 'statSync', 'isDirectory'); -exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); +const factory = options => new Ignore(options) +const returnFalse = () => false -/***/ }), -/* 660 */ -/***/ (function(module, exports, __webpack_require__) { +const isPathValid = path => + checkPath(path && checkPath.convert(path), path, returnFalse) -"use strict"; +factory.isPathValid = isPathValid -const {promisify} = __webpack_require__(29); -const fs = __webpack_require__(23); -const path = __webpack_require__(16); -const fastGlob = __webpack_require__(592); -const gitIgnore = __webpack_require__(661); -const slash = __webpack_require__(662); +// Fixes typescript +factory.default = factory -const DEFAULT_IGNORE = [ - '**/node_modules/**', - '**/flow-typed/**', - '**/coverage/**', - '**/.git' -]; +module.exports = factory -const readFileP = promisify(fs.readFile); +// Windows +// -------------------------------------------------------------- +/* istanbul ignore if */ +if ( + // Detect `process` so that it can run in browsers. + typeof process !== 'undefined' + && ( + process.env && process.env.IGNORE_TEST_WIN32 + || process.platform === 'win32' + ) +) { + /* eslint no-control-regex: "off" */ + const makePosix = str => /^\\\\\?\\/.test(str) + || /["<>|\u0000-\u001F]+/u.test(str) + ? str + : str.replace(/\\/g, '/') -const mapGitIgnorePatternTo = base => ignore => { - if (ignore.startsWith('!')) { - return '!' + path.posix.join(base, ignore.slice(1)); - } + checkPath.convert = makePosix - return path.posix.join(base, ignore); -}; + // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/' + // 'd:\\foo' + const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i + checkPath.isNotRelative = path => + REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path) + || isNotRelative(path) +} -const parseGitIgnore = (content, options) => { - const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); - return content - .split(/\r?\n/) - .filter(Boolean) - .filter(line => !line.startsWith('#')) - .map(mapGitIgnorePatternTo(base)); -}; +/***/ }), +/* 667 */ +/***/ (function(module, exports, __webpack_require__) { -const reduceIgnore = files => { - return files.reduce((ignores, file) => { - ignores.add(parseGitIgnore(file.content, { - cwd: file.cwd, - fileName: file.filePath - })); - return ignores; - }, gitIgnore()); -}; +"use strict"; -const ensureAbsolutePathForCwd = (cwd, p) => { - if (path.isAbsolute(p)) { - if (p.startsWith(cwd)) { - return p; - } +module.exports = path => { + const isExtendedLengthPath = /^\\\\\?\\/.test(path); + const hasNonAscii = /[^\u0000-\u0080]+/.test(path); // eslint-disable-line no-control-regex - throw new Error(`Path ${p} is not in cwd ${cwd}`); + if (isExtendedLengthPath || hasNonAscii) { + return path; } - return path.join(cwd, p); -}; - -const getIsIgnoredPredecate = (ignores, cwd) => { - return p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, p)))); + return path.replace(/\\/g, '/'); }; -const getFile = async (file, cwd) => { - const filePath = path.join(cwd, file); - const content = await readFileP(filePath, 'utf8'); - - return { - cwd, - filePath, - content - }; -}; -const getFileSync = (file, cwd) => { - const filePath = path.join(cwd, file); - const content = fs.readFileSync(filePath, 'utf8'); +/***/ }), +/* 668 */ +/***/ (function(module, exports, __webpack_require__) { - return { - cwd, - filePath, - content - }; -}; +"use strict"; -const normalizeOptions = ({ - ignore = [], - cwd = process.cwd() -} = {}) => { - return {ignore, cwd}; -}; +const {Transform} = __webpack_require__(27); -module.exports = async options => { - options = normalizeOptions(options); +class ObjectTransform extends Transform { + constructor() { + super({ + objectMode: true + }); + } +} - const paths = await fastGlob('**/.gitignore', { - ignore: DEFAULT_IGNORE.concat(options.ignore), - cwd: options.cwd - }); +class FilterStream extends ObjectTransform { + constructor(filter) { + super(); + this._filter = filter; + } - const files = await Promise.all(paths.map(file => getFile(file, options.cwd))); - const ignores = reduceIgnore(files); + _transform(data, encoding, callback) { + if (this._filter(data)) { + this.push(data); + } - return getIsIgnoredPredecate(ignores, options.cwd); -}; + callback(); + } +} -module.exports.sync = options => { - options = normalizeOptions(options); +class UniqueStream extends ObjectTransform { + constructor() { + super(); + this._pushed = new Set(); + } - const paths = fastGlob.sync('**/.gitignore', { - ignore: DEFAULT_IGNORE.concat(options.ignore), - cwd: options.cwd - }); + _transform(data, encoding, callback) { + if (!this._pushed.has(data)) { + this.push(data); + this._pushed.add(data); + } - const files = paths.map(file => getFileSync(file, options.cwd)); - const ignores = reduceIgnore(files); + callback(); + } +} - return getIsIgnoredPredecate(ignores, options.cwd); +module.exports = { + FilterStream, + UniqueStream }; /***/ }), -/* 661 */ -/***/ (function(module, exports) { +/* 669 */ +/***/ (function(module, exports, __webpack_require__) { -// A simple implementation of make-array -function makeArray (subject) { - return Array.isArray(subject) - ? subject - : [subject] -} +"use strict"; -const REGEX_TEST_BLANK_LINE = /^\s+$/ -const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/ -const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/ -const REGEX_SPLITALL_CRLF = /\r?\n/g -// /foo, -// ./foo, -// ../foo, -// . -// .. -const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/ +const path = __webpack_require__(16); -const SLASH = '/' -const KEY_IGNORE = typeof Symbol !== 'undefined' - ? Symbol.for('node-ignore') - /* istanbul ignore next */ - : 'node-ignore' +module.exports = path_ => { + let cwd = process.cwd(); -const define = (object, key, value) => - Object.defineProperty(object, key, {value}) + path_ = path.resolve(path_); -const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g + if (process.platform === 'win32') { + cwd = cwd.toLowerCase(); + path_ = path_.toLowerCase(); + } -// Sanitize the range of a regular expression -// The cases are complicated, see test cases for details -const sanitizeRange = range => range.replace( - REGEX_REGEXP_RANGE, - (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) - ? match - // Invalid range (out of order) which is ok for gitignore rules but - // fatal for JavaScript regular expression, so eliminate it. - : '' -) + return path_ === cwd; +}; -// > If the pattern ends with a slash, -// > it is removed for the purpose of the following description, -// > but it would only find a match with a directory. -// > In other words, foo/ will match a directory foo and paths underneath it, -// > but will not match a regular file or a symbolic link foo -// > (this is consistent with the way how pathspec works in general in Git). -// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`' -// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call -// you could use option `mark: true` with `glob` -// '`foo/`' should not continue with the '`..`' -const DEFAULT_REPLACER_PREFIX = [ +/***/ }), +/* 670 */ +/***/ (function(module, exports, __webpack_require__) { - // > Trailing spaces are ignored unless they are quoted with backslash ("\") - [ - // (a\ ) -> (a ) - // (a ) -> (a) - // (a \ ) -> (a ) - /\\?\s+$/, - match => match.indexOf('\\') === 0 - ? ' ' - : '' - ], +"use strict"; - // replace (\ ) with ' ' - [ - /\\\s/g, - () => ' ' - ], +const path = __webpack_require__(16); - // Escape metacharacters - // which is written down by users but means special for regular expressions. +module.exports = (childPath, parentPath) => { + childPath = path.resolve(childPath); + parentPath = path.resolve(parentPath); - // > There are 12 characters with special meanings: - // > - the backslash \, - // > - the caret ^, - // > - the dollar sign $, - // > - the period or dot ., - // > - the vertical bar or pipe symbol |, - // > - the question mark ?, - // > - the asterisk or star *, - // > - the plus sign +, - // > - the opening parenthesis (, - // > - the closing parenthesis ), - // > - and the opening square bracket [, - // > - the opening curly brace {, - // > These special characters are often called "metacharacters". - [ - /[\\^$.|*+(){]/g, - match => `\\${match}` - ], + if (process.platform === 'win32') { + childPath = childPath.toLowerCase(); + parentPath = parentPath.toLowerCase(); + } - [ - // > [abc] matches any character inside the brackets - // > (in this case a, b, or c); - /\[([^\]/]*)($|\])/g, - (match, p1, p2) => p2 === ']' - ? `[${sanitizeRange(p1)}]` - : `\\${match}` - ], + if (childPath === parentPath) { + return false; + } - [ - // > a question mark (?) matches a single character - /(?!\\)\?/g, - () => '[^/]' - ], + childPath += path.sep; + parentPath += path.sep; - // leading slash - [ + return childPath.startsWith(parentPath); +}; - // > A leading slash matches the beginning of the pathname. - // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". - // A leading slash matches the beginning of the pathname - /^\//, - () => '^' - ], - // replace special metacharacter slash after the leading slash - [ - /\//g, - () => '\\/' - ], +/***/ }), +/* 671 */ +/***/ (function(module, exports, __webpack_require__) { - [ - // > A leading "**" followed by a slash means match in all directories. - // > For example, "**/foo" matches file or directory "foo" anywhere, - // > the same as pattern "foo". - // > "**/foo/bar" matches file or directory "bar" anywhere that is directly - // > under directory "foo". - // Notice that the '*'s have been replaced as '\\*' - /^\^*\\\*\\\*\\\//, +const assert = __webpack_require__(30) +const path = __webpack_require__(16) +const fs = __webpack_require__(23) +let glob = undefined +try { + glob = __webpack_require__(592) +} catch (_err) { + // treat glob as optional. +} - // '**/foo' <-> 'foo' - () => '^(?:.*\\/)?' - ] -] +const defaultGlobOpts = { + nosort: true, + silent: true +} -const DEFAULT_REPLACER_SUFFIX = [ - // starting - [ - // there will be no leading '/' - // (which has been replaced by section "leading slash") - // If starts with '**', adding a '^' to the regular expression also works - /^(?=[^^])/, - function startingReplacer () { - return !/\/(?!$)/.test(this) - // > If the pattern does not contain a slash /, - // > Git treats it as a shell glob pattern - // Actually, if there is only a trailing slash, - // git also treats it as a shell glob pattern - ? '(?:^|\\/)' +// for EMFILE handling +let timeout = 0 - // > Otherwise, Git treats the pattern as a shell glob suitable for - // > consumption by fnmatch(3) - : '^' - } - ], +const isWindows = (process.platform === "win32") - // two globstars - [ - // Use lookahead assertions so that we could match more than one `'/**'` - /\\\/\\\*\\\*(?=\\\/|$)/g, +const defaults = options => { + const methods = [ + 'unlink', + 'chmod', + 'stat', + 'lstat', + 'rmdir', + 'readdir' + ] + methods.forEach(m => { + options[m] = options[m] || fs[m] + m = m + 'Sync' + options[m] = options[m] || fs[m] + }) - // Zero, one or several directories - // should not use '*', or it will be replaced by the next replacer + options.maxBusyTries = options.maxBusyTries || 3 + options.emfileWait = options.emfileWait || 1000 + if (options.glob === false) { + options.disableGlob = true + } + if (options.disableGlob !== true && glob === undefined) { + throw Error('glob dependency not found, set `options.disableGlob = true` if intentional') + } + options.disableGlob = options.disableGlob || false + options.glob = options.glob || defaultGlobOpts +} - // Check if it is not the last `'/**'` - (_, index, str) => index + 6 < str.length +const rimraf = (p, options, cb) => { + if (typeof options === 'function') { + cb = options + options = {} + } - // case: /**/ - // > A slash followed by two consecutive asterisks then a slash matches - // > zero or more directories. - // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on. - // '/**/' - ? '(?:\\/[^\\/]+)*' + assert(p, 'rimraf: missing path') + assert.equal(typeof p, 'string', 'rimraf: path should be a string') + assert.equal(typeof cb, 'function', 'rimraf: callback function required') + assert(options, 'rimraf: invalid options argument provided') + assert.equal(typeof options, 'object', 'rimraf: options should be object') - // case: /** - // > A trailing `"/**"` matches everything inside. + defaults(options) - // #21: everything inside but it should not include the current folder - : '\\/.+' - ], + let busyTries = 0 + let errState = null + let n = 0 - // intermediate wildcards - [ - // Never replace escaped '*' - // ignore rule '\*' will match the path '*' + const next = (er) => { + errState = errState || er + if (--n === 0) + cb(errState) + } - // 'abc.*/' -> go - // 'abc.*' -> skip this rule - /(^|[^\\]+)\\\*(?=.+)/g, + const afterGlob = (er, results) => { + if (er) + return cb(er) - // '*.js' matches '.js' - // '*.js' doesn't match 'abc' - (_, p1) => `${p1}[^\\/]*` - ], + n = results.length + if (n === 0) + return cb() - // trailing wildcard - [ - /(\^|\\\/)?\\\*$/, - (_, p1) => { - const prefix = p1 - // '\^': - // '/*' does not match '' - // '/*' does not match everything + results.forEach(p => { + const CB = (er) => { + if (er) { + if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && + busyTries < options.maxBusyTries) { + busyTries ++ + // try again, with the same exact callback as this one. + return setTimeout(() => rimraf_(p, options, CB), busyTries * 100) + } - // '\\\/': - // 'abc/*' does not match 'abc/' - ? `${p1}[^/]+` + // this one won't happen if graceful-fs is used. + if (er.code === "EMFILE" && timeout < options.emfileWait) { + return setTimeout(() => rimraf_(p, options, CB), timeout ++) + } - // 'a*' matches 'a' - // 'a*' matches 'aa' - : '[^/]*' + // already gone + if (er.code === "ENOENT") er = null + } - return `${prefix}(?=$|\\/$)` - } - ], + timeout = 0 + next(er) + } + rimraf_(p, options, CB) + }) + } - [ - // unescape - /\\\\\\/g, - () => '\\' - ] -] + if (options.disableGlob || !glob.hasMagic(p)) + return afterGlob(null, [p]) -const POSITIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, + options.lstat(p, (er, stat) => { + if (!er) + return afterGlob(null, [p]) - // 'f' - // matches - // - /f(end) - // - /f/ - // - (start)f(end) - // - (start)f/ - // doesn't match - // - oof - // - foo - // pseudo: - // -> (^|/)f(/|$) + glob(p, options.glob, afterGlob) + }) - // ending - [ - // 'js' will not match 'js.' - // 'ab' will not match 'abc' - /(?:[^*/])$/, +} - // 'js*' will not match 'a.js' - // 'js/' will not match 'a.js' - // 'js' will match 'a.js' and 'a.js/' - match => `${match}(?=$|\\/)` - ], +// Two possible strategies. +// 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR +// 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR +// +// Both result in an extra syscall when you guess wrong. However, there +// are likely far more normal files in the world than directories. This +// is based on the assumption that a the average number of files per +// directory is >= 1. +// +// If anyone ever complains about this, then I guess the strategy could +// be made configurable somehow. But until then, YAGNI. +const rimraf_ = (p, options, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') - ...DEFAULT_REPLACER_SUFFIX -] + // sunos lets the root user unlink directories, which is... weird. + // so we have to lstat here and make sure it's not a dir. + options.lstat(p, (er, st) => { + if (er && er.code === "ENOENT") + return cb(null) -const NEGATIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, + // Windows can EPERM on stat. Life is suffering. + if (er && er.code === "EPERM" && isWindows) + fixWinEPERM(p, options, er, cb) - // #24, #38 - // The MISSING rule of [gitignore docs](https://git-scm.com/docs/gitignore) - // A negative pattern without a trailing wildcard should not - // re-include the things inside that directory. + if (st && st.isDirectory()) + return rmdir(p, options, er, cb) - // eg: - // ['node_modules/*', '!node_modules'] - // should ignore `node_modules/a.js` - [ - /(?:[^*])$/, - match => `${match}(?=$|\\/$)` - ], + options.unlink(p, er => { + if (er) { + if (er.code === "ENOENT") + return cb(null) + if (er.code === "EPERM") + return (isWindows) + ? fixWinEPERM(p, options, er, cb) + : rmdir(p, options, er, cb) + if (er.code === "EISDIR") + return rmdir(p, options, er, cb) + } + return cb(er) + }) + }) +} - ...DEFAULT_REPLACER_SUFFIX -] +const fixWinEPERM = (p, options, er, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') + if (er) + assert(er instanceof Error) -// A simple cache, because an ignore rule only has only one certain meaning -const regexCache = Object.create(null) + options.chmod(p, 0o666, er2 => { + if (er2) + cb(er2.code === "ENOENT" ? null : er) + else + options.stat(p, (er3, stats) => { + if (er3) + cb(er3.code === "ENOENT" ? null : er) + else if (stats.isDirectory()) + rmdir(p, options, er, cb) + else + options.unlink(p, cb) + }) + }) +} -// @param {pattern} -const makeRegex = (pattern, negative, ignorecase) => { - const r = regexCache[pattern] - if (r) { - return r +const fixWinEPERMSync = (p, options, er) => { + assert(p) + assert(options) + if (er) + assert(er instanceof Error) + + try { + options.chmodSync(p, 0o666) + } catch (er2) { + if (er2.code === "ENOENT") + return + else + throw er } - const replacers = negative - ? NEGATIVE_REPLACERS - : POSITIVE_REPLACERS + let stats + try { + stats = options.statSync(p) + } catch (er3) { + if (er3.code === "ENOENT") + return + else + throw er + } - const source = replacers.reduce( - (prev, current) => prev.replace(current[0], current[1].bind(pattern)), - pattern - ) + if (stats.isDirectory()) + rmdirSync(p, options, er) + else + options.unlinkSync(p) +} - return regexCache[pattern] = ignorecase - ? new RegExp(source, 'i') - : new RegExp(source) +const rmdir = (p, options, originalEr, cb) => { + assert(p) + assert(options) + if (originalEr) + assert(originalEr instanceof Error) + assert(typeof cb === 'function') + + // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS) + // if we guessed wrong, and it's not a directory, then + // raise the original error. + options.rmdir(p, er => { + if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")) + rmkids(p, options, cb) + else if (er && er.code === "ENOTDIR") + cb(originalEr) + else + cb(er) + }) } -const isString = subject => typeof subject === 'string' +const rmkids = (p, options, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') -// > A blank line matches no files, so it can serve as a separator for readability. -const checkPattern = pattern => pattern - && isString(pattern) - && !REGEX_TEST_BLANK_LINE.test(pattern) + options.readdir(p, (er, files) => { + if (er) + return cb(er) + let n = files.length + if (n === 0) + return options.rmdir(p, cb) + let errState + files.forEach(f => { + rimraf(path.join(p, f), options, er => { + if (errState) + return + if (er) + return cb(errState = er) + if (--n === 0) + options.rmdir(p, cb) + }) + }) + }) +} - // > A line starting with # serves as a comment. - && pattern.indexOf('#') !== 0 +// this looks simpler, and is strictly *faster*, but will +// tie up the JavaScript thread and fail on excessively +// deep directory trees. +const rimrafSync = (p, options) => { + options = options || {} + defaults(options) -const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF) + assert(p, 'rimraf: missing path') + assert.equal(typeof p, 'string', 'rimraf: path should be a string') + assert(options, 'rimraf: missing options') + assert.equal(typeof options, 'object', 'rimraf: options should be object') -class IgnoreRule { - constructor ( - origin, - pattern, - negative, - regex - ) { - this.origin = origin - this.pattern = pattern - this.negative = negative - this.regex = regex + let results + + if (options.disableGlob || !glob.hasMagic(p)) { + results = [p] + } else { + try { + options.lstatSync(p) + results = [p] + } catch (er) { + results = glob.sync(p, options.glob) + } } -} -const createRule = (pattern, ignorecase) => { - const origin = pattern - let negative = false + if (!results.length) + return - // > An optional prefix "!" which negates the pattern; - if (pattern.indexOf('!') === 0) { - negative = true - pattern = pattern.substr(1) - } + for (let i = 0; i < results.length; i++) { + const p = results[i] - pattern = pattern - // > Put a backslash ("\") in front of the first "!" for patterns that - // > begin with a literal "!", for example, `"\!important!.txt"`. - .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!') - // > Put a backslash ("\") in front of the first hash for patterns that - // > begin with a hash. - .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#') + let st + try { + st = options.lstatSync(p) + } catch (er) { + if (er.code === "ENOENT") + return - const regex = makeRegex(pattern, negative, ignorecase) + // Windows can EPERM on stat. Life is suffering. + if (er.code === "EPERM" && isWindows) + fixWinEPERMSync(p, options, er) + } - return new IgnoreRule( - origin, - pattern, - negative, - regex - ) -} + try { + // sunos lets the root user unlink directories, which is... weird. + if (st && st.isDirectory()) + rmdirSync(p, options, null) + else + options.unlinkSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code === "EPERM") + return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er) + if (er.code !== "EISDIR") + throw er -const throwError = (message, Ctor) => { - throw new Ctor(message) + rmdirSync(p, options, er) + } + } } -const checkPath = (path, originalPath, doThrow) => { - if (!isString(path)) { - return doThrow( - `path must be a string, but got \`${originalPath}\``, - TypeError - ) - } +const rmdirSync = (p, options, originalEr) => { + assert(p) + assert(options) + if (originalEr) + assert(originalEr instanceof Error) - // We don't know if we should ignore '', so throw - if (!path) { - return doThrow(`path must not be empty`, TypeError) + try { + options.rmdirSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code === "ENOTDIR") + throw originalEr + if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM") + rmkidsSync(p, options) } +} - // Check if it is a relative path - if (checkPath.isNotRelative(path)) { - const r = '`path.relative()`d' - return doThrow( - `path should be a ${r} string, but got "${originalPath}"`, - RangeError - ) - } +const rmkidsSync = (p, options) => { + assert(p) + assert(options) + options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options)) - return true + // We only end up here once we got ENOTEMPTY at least once, and + // at this point, we are guaranteed to have removed all the kids. + // So, we know that it won't be ENOENT or ENOTDIR or anything else. + // try really hard to delete stuff on windows, because it has a + // PROFOUNDLY annoying habit of not closing handles promptly when + // files are deleted, resulting in spurious ENOTEMPTY errors. + const retries = isWindows ? 100 : 1 + let i = 0 + do { + let threw = true + try { + const ret = options.rmdirSync(p, options) + threw = false + return ret + } finally { + if (++i < retries && threw) + continue + } + } while (true) } -const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path) +module.exports = rimraf +rimraf.sync = rimrafSync -checkPath.isNotRelative = isNotRelative -checkPath.convert = p => p -class Ignore { - constructor ({ - ignorecase = true - } = {}) { - this._rules = [] - this._ignorecase = ignorecase - define(this, KEY_IGNORE, true) - this._initCache() - } +/***/ }), +/* 672 */ +/***/ (function(module, exports, __webpack_require__) { - _initCache () { - this._ignoreCache = Object.create(null) - this._testCache = Object.create(null) - } +"use strict"; - _addPattern (pattern) { - // #32 - if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat(pattern._rules) - this._added = true - return - } +const AggregateError = __webpack_require__(673); - if (checkPattern(pattern)) { - const rule = createRule(pattern, this._ignorecase) - this._added = true - this._rules.push(rule) - } - } +module.exports = async ( + iterable, + mapper, + { + concurrency = Infinity, + stopOnError = true + } = {} +) => { + return new Promise((resolve, reject) => { + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); + } - // @param {Array | string | Ignore} pattern - add (pattern) { - this._added = false + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } - makeArray( - isString(pattern) - ? splitPattern(pattern) - : pattern - ).forEach(this._addPattern, this) + const ret = []; + const errors = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; - // Some rules have just added to the ignore, - // making the behavior changed. - if (this._added) { - this._initCache() - } + const next = () => { + if (isRejected) { + return; + } - return this - } + const nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; - // legacy - addPattern (pattern) { - return this.add(pattern) - } + if (nextItem.done) { + isIterableDone = true; - // | ignored : unignored - // negative | 0:0 | 0:1 | 1:0 | 1:1 - // -------- | ------- | ------- | ------- | -------- - // 0 | TEST | TEST | SKIP | X - // 1 | TESTIF | SKIP | TEST | X + if (resolvingCount === 0) { + if (!stopOnError && errors.length !== 0) { + reject(new AggregateError(errors)); + } else { + resolve(ret); + } + } - // - SKIP: always skip - // - TEST: always test - // - TESTIF: only test if checkUnignored - // - X: that never happen + return; + } - // @param {boolean} whether should check if the path is unignored, - // setting `checkUnignored` to `false` could reduce additional - // path matching. + resolvingCount++; - // @returns {TestResult} true if a file is ignored - _testOne (path, checkUnignored) { - let ignored = false - let unignored = false + (async () => { + try { + const element = await nextItem.value; + ret[i] = await mapper(element, i); + resolvingCount--; + next(); + } catch (error) { + if (stopOnError) { + isRejected = true; + reject(error); + } else { + errors.push(error); + resolvingCount--; + next(); + } + } + })(); + }; - this._rules.forEach(rule => { - const {negative} = rule - if ( - unignored === negative && ignored !== unignored - || negative && !ignored && !unignored && !checkUnignored - ) { - return - } + for (let i = 0; i < concurrency; i++) { + next(); - const matched = rule.regex.test(path) + if (isIterableDone) { + break; + } + } + }); +}; - if (matched) { - ignored = !negative - unignored = negative - } - }) - return { - ignored, - unignored - } - } +/***/ }), +/* 673 */ +/***/ (function(module, exports, __webpack_require__) { - // @returns {TestResult} - _test (originalPath, cache, checkUnignored, slices) { - const path = originalPath - // Supports nullable path - && checkPath.convert(originalPath) +"use strict"; - checkPath(path, originalPath, throwError) +const indentString = __webpack_require__(674); +const cleanStack = __webpack_require__(675); - return this._t(path, cache, checkUnignored, slices) - } +const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); - _t (path, cache, checkUnignored, slices) { - if (path in cache) { - return cache[path] - } +class AggregateError extends Error { + constructor(errors) { + if (!Array.isArray(errors)) { + throw new TypeError(`Expected input to be an Array, got ${typeof errors}`); + } - if (!slices) { - // path/to/a.js - // ['path', 'to', 'a.js'] - slices = path.split(SLASH) - } + errors = [...errors].map(error => { + if (error instanceof Error) { + return error; + } - slices.pop() + if (error !== null && typeof error === 'object') { + // Handle plain error objects with message property and/or possibly other metadata + return Object.assign(new Error(error.message), error); + } - // If the path has no parent directory, just test it - if (!slices.length) { - return cache[path] = this._testOne(path, checkUnignored) - } + return new Error(error); + }); - const parent = this._t( - slices.join(SLASH) + SLASH, - cache, - checkUnignored, - slices - ) + let message = errors + .map(error => { + // The `stack` property is not standardized, so we can't assume it exists + return typeof error.stack === 'string' ? cleanInternalStack(cleanStack(error.stack)) : String(error); + }) + .join('\n'); + message = '\n' + indentString(message, 4); + super(message); - // If the path contains a parent directory, check the parent first - return cache[path] = parent.ignored - // > It is not possible to re-include a file if a parent directory of - // > that file is excluded. - ? parent - : this._testOne(path, checkUnignored) - } + this.name = 'AggregateError'; - ignores (path) { - return this._test(path, this._ignoreCache, false).ignored - } + Object.defineProperty(this, '_errors', {value: errors}); + } - createFilter () { - return path => !this.ignores(path) - } + * [Symbol.iterator]() { + for (const error of this._errors) { + yield error; + } + } +} - filter (paths) { - return makeArray(paths).filter(this.createFilter()) - } +module.exports = AggregateError; - // @returns {TestResult} - test (path) { - return this._test(path, this._testCache, true) - } -} -const factory = options => new Ignore(options) +/***/ }), +/* 674 */ +/***/ (function(module, exports, __webpack_require__) { -const returnFalse = () => false +"use strict"; -const isPathValid = path => - checkPath(path && checkPath.convert(path), path, returnFalse) -factory.isPathValid = isPathValid +module.exports = (string, count = 1, options) => { + options = { + indent: ' ', + includeEmptyLines: false, + ...options + }; -// Fixes typescript -factory.default = factory + if (typeof string !== 'string') { + throw new TypeError( + `Expected \`input\` to be a \`string\`, got \`${typeof string}\`` + ); + } -module.exports = factory + if (typeof count !== 'number') { + throw new TypeError( + `Expected \`count\` to be a \`number\`, got \`${typeof count}\`` + ); + } -// Windows -// -------------------------------------------------------------- -/* istanbul ignore if */ -if ( - // Detect `process` so that it can run in browsers. - typeof process !== 'undefined' - && ( - process.env && process.env.IGNORE_TEST_WIN32 - || process.platform === 'win32' - ) -) { - /* eslint no-control-regex: "off" */ - const makePosix = str => /^\\\\\?\\/.test(str) - || /["<>|\u0000-\u001F]+/u.test(str) - ? str - : str.replace(/\\/g, '/') + if (typeof options.indent !== 'string') { + throw new TypeError( + `Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\`` + ); + } - checkPath.convert = makePosix + if (count === 0) { + return string; + } - // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/' - // 'd:\\foo' - const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i - checkPath.isNotRelative = path => - REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path) - || isNotRelative(path) -} + const regex = options.includeEmptyLines ? /^/gm : /^(?!\s*$)/gm; + + return string.replace(regex, options.indent.repeat(count)); +}; /***/ }), -/* 662 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = path => { - const isExtendedLengthPath = /^\\\\\?\\/.test(path); - const hasNonAscii = /[^\u0000-\u0080]+/.test(path); // eslint-disable-line no-control-regex +const os = __webpack_require__(11); - if (isExtendedLengthPath || hasNonAscii) { - return path; - } +const extractPathRegex = /\s+at.*(?:\(|\s)(.*)\)?/; +const pathRegex = /^(?:(?:(?:node|(?:internal\/[\w/]*|.*node_modules\/(?:babel-polyfill|pirates)\/.*)?\w+)\.js:\d+:\d+)|native)/; +const homeDir = typeof os.homedir === 'undefined' ? '' : os.homedir(); + +module.exports = (stack, options) => { + options = Object.assign({pretty: false}, options); + + return stack.replace(/\\/g, '/') + .split('\n') + .filter(line => { + const pathMatches = line.match(extractPathRegex); + if (pathMatches === null || !pathMatches[1]) { + return true; + } + + const match = pathMatches[1]; + + // Electron + if ( + match.includes('.app/Contents/Resources/electron.asar') || + match.includes('.app/Contents/Resources/default_app.asar') + ) { + return false; + } + + return !pathRegex.test(match); + }) + .filter(line => line.trim() !== '') + .map(line => { + if (options.pretty) { + return line.replace(extractPathRegex, (m, p1) => m.replace(p1, p1.replace(homeDir, '~'))); + } - return path.replace(/\\/g, '/'); + return line; + }) + .join('\n'); }; /***/ }), -/* 663 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const {Transform} = __webpack_require__(27); +const chalk = __webpack_require__(677); +const cliCursor = __webpack_require__(681); +const cliSpinners = __webpack_require__(685); +const logSymbols = __webpack_require__(566); -class ObjectTransform extends Transform { - constructor() { - super({ - objectMode: true - }); - } -} +class Ora { + constructor(options) { + if (typeof options === 'string') { + options = { + text: options + }; + } -class FilterStream extends ObjectTransform { - constructor(filter) { - super(); - this._filter = filter; - } + this.options = Object.assign({ + text: '', + color: 'cyan', + stream: process.stderr + }, options); - _transform(data, encoding, callback) { - if (this._filter(data)) { - this.push(data); - } + const sp = this.options.spinner; + this.spinner = typeof sp === 'object' ? sp : (process.platform === 'win32' ? cliSpinners.line : (cliSpinners[sp] || cliSpinners.dots)); // eslint-disable-line no-nested-ternary - callback(); - } -} + if (this.spinner.frames === undefined) { + throw new Error('Spinner must define `frames`'); + } -class UniqueStream extends ObjectTransform { - constructor() { - super(); - this._pushed = new Set(); + this.text = this.options.text; + this.color = this.options.color; + this.interval = this.options.interval || this.spinner.interval || 100; + this.stream = this.options.stream; + this.id = null; + this.frameIndex = 0; + this.enabled = typeof this.options.enabled === 'boolean' ? this.options.enabled : ((this.stream && this.stream.isTTY) && !process.env.CI); } + frame() { + const frames = this.spinner.frames; + let frame = frames[this.frameIndex]; - _transform(data, encoding, callback) { - if (!this._pushed.has(data)) { - this.push(data); - this._pushed.add(data); + if (this.color) { + frame = chalk[this.color](frame); } - callback(); - } -} + this.frameIndex = ++this.frameIndex % frames.length; -module.exports = { - FilterStream, - UniqueStream -}; + return frame + ' ' + this.text; + } + clear() { + if (!this.enabled) { + return this; + } + this.stream.clearLine(); + this.stream.cursorTo(0); -/***/ }), -/* 664 */ -/***/ (function(module, exports, __webpack_require__) { + return this; + } + render() { + this.clear(); + this.stream.write(this.frame()); -var fs = __webpack_require__(23) -var polyfills = __webpack_require__(665) -var legacy = __webpack_require__(666) -var clone = __webpack_require__(667) + return this; + } + start(text) { + if (text) { + this.text = text; + } -var util = __webpack_require__(29) + if (!this.enabled || this.id) { + return this; + } -/* istanbul ignore next - node 0.x polyfill */ -var gracefulQueue -var previousSymbol + cliCursor.hide(this.stream); + this.render(); + this.id = setInterval(this.render.bind(this), this.interval); -/* istanbul ignore else - node 0.x polyfill */ -if (typeof Symbol === 'function' && typeof Symbol.for === 'function') { - gracefulQueue = Symbol.for('graceful-fs.queue') - // This is used in testing by future versions - previousSymbol = Symbol.for('graceful-fs.previous') -} else { - gracefulQueue = '___graceful-fs.queue' - previousSymbol = '___graceful-fs.previous' -} + return this; + } + stop() { + if (!this.enabled) { + return this; + } -function noop () {} + clearInterval(this.id); + this.id = null; + this.frameIndex = 0; + this.clear(); + cliCursor.show(this.stream); -var debug = noop -if (util.debuglog) - debug = util.debuglog('gfs4') -else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) - debug = function() { - var m = util.format.apply(util, arguments) - m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: ') - console.error(m) - } + return this; + } + succeed(text) { + return this.stopAndPersist({symbol: logSymbols.success, text}); + } + fail(text) { + return this.stopAndPersist({symbol: logSymbols.error, text}); + } + warn(text) { + return this.stopAndPersist({symbol: logSymbols.warning, text}); + } + info(text) { + return this.stopAndPersist({symbol: logSymbols.info, text}); + } + stopAndPersist(options) { + if (!this.enabled) { + return this; + } -// Once time initialization -if (!global[gracefulQueue]) { - // This queue can be shared by multiple loaded instances - var queue = [] - Object.defineProperty(global, gracefulQueue, { - get: function() { - return queue - } - }) + // Legacy argument + // TODO: Deprecate sometime in the future + if (typeof options === 'string') { + options = { + symbol: options + }; + } - // Patch fs.close/closeSync to shared queue version, because we need - // to retry() whenever a close happens *anywhere* in the program. - // This is essential when multiple graceful-fs instances are - // in play at the same time. - fs.close = (function (fs$close) { - function close (fd, cb) { - return fs$close.call(fs, fd, function (err) { - // This function uses the graceful-fs shared queue - if (!err) { - retry() - } + options = options || {}; - if (typeof cb === 'function') - cb.apply(this, arguments) - }) - } + this.stop(); + this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); - Object.defineProperty(close, previousSymbol, { - value: fs$close - }) - return close - })(fs.close) + return this; + } +} - fs.closeSync = (function (fs$closeSync) { - function closeSync (fd) { - // This function uses the graceful-fs shared queue - fs$closeSync.apply(fs, arguments) - retry() - } +module.exports = function (opts) { + return new Ora(opts); +}; - Object.defineProperty(closeSync, previousSymbol, { - value: fs$closeSync - }) - return closeSync - })(fs.closeSync) +module.exports.promise = (action, options) => { + if (typeof action.then !== 'function') { + throw new TypeError('Parameter `action` must be a Promise'); + } - if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { - process.on('exit', function() { - debug(global[gracefulQueue]) - __webpack_require__(30).equal(global[gracefulQueue].length, 0) - }) - } -} + const spinner = new Ora(options); + spinner.start(); -module.exports = patch(clone(fs)) -if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { - module.exports = patch(fs) - fs.__patched = true; -} + action.then( + () => { + spinner.succeed(); + }, + () => { + spinner.fail(); + } + ); -function patch (fs) { - // Everything that references the open() function needs to be in here - polyfills(fs) - fs.gracefulify = patch + return spinner; +}; - fs.createReadStream = createReadStream - fs.createWriteStream = createWriteStream - var fs$readFile = fs.readFile - fs.readFile = readFile - function readFile (path, options, cb) { - if (typeof options === 'function') - cb = options, options = null - return go$readFile(path, options, cb) +/***/ }), +/* 677 */ +/***/ (function(module, exports, __webpack_require__) { - function go$readFile (path, options, cb) { - return fs$readFile(path, options, function (err) { - if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) - enqueue([go$readFile, [path, options, cb]]) - else { - if (typeof cb === 'function') - cb.apply(this, arguments) - retry() - } - }) - } - } +"use strict"; - var fs$writeFile = fs.writeFile - fs.writeFile = writeFile - function writeFile (path, data, options, cb) { - if (typeof options === 'function') - cb = options, options = null +const escapeStringRegexp = __webpack_require__(3); +const ansiStyles = __webpack_require__(678); +const stdoutColor = __webpack_require__(679).stdout; - return go$writeFile(path, data, options, cb) +const template = __webpack_require__(680); - function go$writeFile (path, data, options, cb) { - return fs$writeFile(path, data, options, function (err) { - if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) - enqueue([go$writeFile, [path, data, options, cb]]) - else { - if (typeof cb === 'function') - cb.apply(this, arguments) - retry() - } - }) - } - } +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); - var fs$appendFile = fs.appendFile - if (fs$appendFile) - fs.appendFile = appendFile - function appendFile (path, data, options, cb) { - if (typeof options === 'function') - cb = options, options = null +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; - return go$appendFile(path, data, options, cb) +// `color-convert` models to exclude from the Chalk API due to conflicts and such +const skipModels = new Set(['gray']); - function go$appendFile (path, data, options, cb) { - return fs$appendFile(path, data, options, function (err) { - if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) - enqueue([go$appendFile, [path, data, options, cb]]) - else { - if (typeof cb === 'function') - cb.apply(this, arguments) - retry() - } - }) - } - } +const styles = Object.create(null); - var fs$readdir = fs.readdir - fs.readdir = readdir - function readdir (path, options, cb) { - var args = [path] - if (typeof options !== 'function') { - args.push(options) - } else { - cb = options - } - args.push(go$readdir$cb) +function applyOptions(obj, options) { + options = options || {}; - return go$readdir(args) + // Detect level if not set manually + const scLevel = stdoutColor ? stdoutColor.level : 0; + obj.level = options.level === undefined ? scLevel : options.level; + obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; +} - function go$readdir$cb (err, files) { - if (files && files.sort) - files.sort() +function Chalk(options) { + // We check for this.template here since calling `chalk.constructor()` + // by itself will have a `this` of a previously constructed chalk object + if (!this || !(this instanceof Chalk) || this.template) { + const chalk = {}; + applyOptions(chalk, options); - if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) - enqueue([go$readdir, [args]]) + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; - else { - if (typeof cb === 'function') - cb.apply(this, arguments) - retry() - } - } - } + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); - function go$readdir (args) { - return fs$readdir.apply(fs, args) - } + chalk.template.constructor = Chalk; - if (process.version.substr(0, 4) === 'v0.8') { - var legStreams = legacy(fs) - ReadStream = legStreams.ReadStream - WriteStream = legStreams.WriteStream - } + return chalk.template; + } - var fs$ReadStream = fs.ReadStream - if (fs$ReadStream) { - ReadStream.prototype = Object.create(fs$ReadStream.prototype) - ReadStream.prototype.open = ReadStream$open - } + applyOptions(this, options); +} - var fs$WriteStream = fs.WriteStream - if (fs$WriteStream) { - WriteStream.prototype = Object.create(fs$WriteStream.prototype) - WriteStream.prototype.open = WriteStream$open - } +// Use bright blue on Windows as the normal blue color is illegible +if (isSimpleWindowsTerm) { + ansiStyles.blue.open = '\u001B[94m'; +} - Object.defineProperty(fs, 'ReadStream', { - get: function () { - return ReadStream - }, - set: function (val) { - ReadStream = val - }, - enumerable: true, - configurable: true - }) - Object.defineProperty(fs, 'WriteStream', { - get: function () { - return WriteStream - }, - set: function (val) { - WriteStream = val - }, - enumerable: true, - configurable: true - }) +for (const key of Object.keys(ansiStyles)) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); - // legacy names - Object.defineProperty(fs, 'FileReadStream', { - get: function () { - return ReadStream - }, - set: function (val) { - ReadStream = val - }, - enumerable: true, - configurable: true - }) - Object.defineProperty(fs, 'FileWriteStream', { - get: function () { - return WriteStream - }, - set: function (val) { - WriteStream = val - }, - enumerable: true, - configurable: true - }) + styles[key] = { + get() { + const codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + } + }; +} - function ReadStream (path, options) { - if (this instanceof ReadStream) - return fs$ReadStream.apply(this, arguments), this - else - return ReadStream.apply(Object.create(ReadStream.prototype), arguments) - } +styles.visible = { + get() { + return build.call(this, this._styles || [], true, 'visible'); + } +}; - function ReadStream$open () { - var that = this - open(that.path, that.flags, that.mode, function (err, fd) { - if (err) { - if (that.autoClose) - that.destroy() +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +for (const model of Object.keys(ansiStyles.color.ansi)) { + if (skipModels.has(model)) { + continue; + } - that.emit('error', err) - } else { - that.fd = fd - that.emit('open', fd) - that.read() - } - }) - } + styles[model] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.color.close, + closeRe: ansiStyles.color.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} - function WriteStream (path, options) { - if (this instanceof WriteStream) - return fs$WriteStream.apply(this, arguments), this - else - return WriteStream.apply(Object.create(WriteStream.prototype), arguments) - } +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { + if (skipModels.has(model)) { + continue; + } - function WriteStream$open () { - var that = this - open(that.path, that.flags, that.mode, function (err, fd) { - if (err) { - that.destroy() - that.emit('error', err) - } else { - that.fd = fd - that.emit('open', fd) - } - }) - } + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.bgColor.close, + closeRe: ansiStyles.bgColor.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} - function createReadStream (path, options) { - return new fs.ReadStream(path, options) - } +const proto = Object.defineProperties(() => {}, styles); - function createWriteStream (path, options) { - return new fs.WriteStream(path, options) - } +function build(_styles, _empty, key) { + const builder = function () { + return applyStyle.apply(builder, arguments); + }; - var fs$open = fs.open - fs.open = open - function open (path, flags, mode, cb) { - if (typeof mode === 'function') - cb = mode, mode = null + builder._styles = _styles; + builder._empty = _empty; - return go$open(path, flags, mode, cb) + const self = this; - function go$open (path, flags, mode, cb) { - return fs$open(path, flags, mode, function (err, fd) { - if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) - enqueue([go$open, [path, flags, mode, cb]]) - else { - if (typeof cb === 'function') - cb.apply(this, arguments) - retry() - } - }) - } - } + Object.defineProperty(builder, 'level', { + enumerable: true, + get() { + return self.level; + }, + set(level) { + self.level = level; + } + }); - return fs -} + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); -function enqueue (elem) { - debug('ENQUEUE', elem[0].name, elem[1]) - global[gracefulQueue].push(elem) -} + // See below for fix regarding invisible grey/dim combination on Windows + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; -function retry () { - var elem = global[gracefulQueue].shift() - if (elem) { - debug('RETRY', elem[0].name, elem[1]) - elem[0].apply(null, elem[1]) - } + // `__proto__` is used because we must return a function, but there is + // no way to create a function with a different prototype + builder.__proto__ = proto; // eslint-disable-line no-proto + + return builder; } +function applyStyle() { + // Support varags, but simply cast to string in case there's only one arg + const args = arguments; + const argsLen = args.length; + let str = String(arguments[0]); -/***/ }), -/* 665 */ -/***/ (function(module, exports, __webpack_require__) { + if (argsLen === 0) { + return ''; + } -var constants = __webpack_require__(25) + if (argsLen > 1) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { + str += ' ' + args[a]; + } + } -var origCwd = process.cwd -var cwd = null + if (!this.enabled || this.level <= 0 || !str) { + return this._empty ? '' : str; + } -var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform + // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, + // see https://github.com/chalk/chalk/issues/58 + // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. + const originalDim = ansiStyles.dim.open; + if (isSimpleWindowsTerm && this.hasGrey) { + ansiStyles.dim.open = ''; + } -process.cwd = function() { - if (!cwd) - cwd = origCwd.call(process) - return cwd -} -try { - process.cwd() -} catch (er) {} + for (const code of this._styles.slice().reverse()) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + str = code.open + str.replace(code.closeRe, code.open) + code.close; -var chdir = process.chdir -process.chdir = function(d) { - cwd = null - chdir.call(process, d) -} + // Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS + // https://github.com/chalk/chalk/pull/92 + str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + } -module.exports = patch + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue + ansiStyles.dim.open = originalDim; -function patch (fs) { - // (re-)implement some things that are known busted or missing. + return str; +} - // lchmod, broken prior to 0.6.2 - // back-port the fix here. - if (constants.hasOwnProperty('O_SYMLINK') && - process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) { - patchLchmod(fs) - } +function chalkTag(chalk, strings) { + if (!Array.isArray(strings)) { + // If chalk() was called by itself or with a string, + // return the string itself as a string. + return [].slice.call(arguments, 1).join(' '); + } - // lutimes implementation, or no-op - if (!fs.lutimes) { - patchLutimes(fs) - } + const args = [].slice.call(arguments, 2); + const parts = [strings.raw[0]]; - // https://github.com/isaacs/node-graceful-fs/issues/4 - // Chown should not fail on einval or eperm if non-root. - // It should not fail on enosys ever, as this just indicates - // that a fs doesn't support the intended operation. + for (let i = 1; i < strings.length; i++) { + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); + } - fs.chown = chownFix(fs.chown) - fs.fchown = chownFix(fs.fchown) - fs.lchown = chownFix(fs.lchown) + return template(chalk, parts.join('')); +} - fs.chmod = chmodFix(fs.chmod) - fs.fchmod = chmodFix(fs.fchmod) - fs.lchmod = chmodFix(fs.lchmod) +Object.defineProperties(Chalk.prototype, styles); - fs.chownSync = chownFixSync(fs.chownSync) - fs.fchownSync = chownFixSync(fs.fchownSync) - fs.lchownSync = chownFixSync(fs.lchownSync) +module.exports = Chalk(); // eslint-disable-line new-cap +module.exports.supportsColor = stdoutColor; +module.exports.default = module.exports; // For TypeScript - fs.chmodSync = chmodFixSync(fs.chmodSync) - fs.fchmodSync = chmodFixSync(fs.fchmodSync) - fs.lchmodSync = chmodFixSync(fs.lchmodSync) - fs.stat = statFix(fs.stat) - fs.fstat = statFix(fs.fstat) - fs.lstat = statFix(fs.lstat) +/***/ }), +/* 678 */ +/***/ (function(module, exports, __webpack_require__) { - fs.statSync = statFixSync(fs.statSync) - fs.fstatSync = statFixSync(fs.fstatSync) - fs.lstatSync = statFixSync(fs.lstatSync) +"use strict"; +/* WEBPACK VAR INJECTION */(function(module) { +const colorConvert = __webpack_require__(6); - // if lchmod/lchown do not exist, then make them no-ops - if (!fs.lchmod) { - fs.lchmod = function (path, mode, cb) { - if (cb) process.nextTick(cb) - } - fs.lchmodSync = function () {} - } - if (!fs.lchown) { - fs.lchown = function (path, uid, gid, cb) { - if (cb) process.nextTick(cb) - } - fs.lchownSync = function () {} - } +const wrapAnsi16 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${code + offset}m`; +}; - // on Windows, A/V software can lock the directory, causing this - // to fail with an EACCES or EPERM if the directory contains newly - // created files. Try again on failure, for up to 60 seconds. +const wrapAnsi256 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};5;${code}m`; +}; - // Set the timeout this long because some Windows Anti-Virus, such as Parity - // bit9, may lock files for up to a minute, causing npm package install - // failures. Also, take care to yield the scheduler. Windows scheduling gives - // CPU to a busy looping process, which can cause the program causing the lock - // contention to be starved of CPU by node, so the contention doesn't resolve. - if (platform === "win32") { - fs.rename = (function (fs$rename) { return function (from, to, cb) { - var start = Date.now() - var backoff = 0; - fs$rename(from, to, function CB (er) { - if (er - && (er.code === "EACCES" || er.code === "EPERM") - && Date.now() - start < 60000) { - setTimeout(function() { - fs.stat(to, function (stater, st) { - if (stater && stater.code === "ENOENT") - fs$rename(from, to, CB); - else - cb(er) - }) - }, backoff) - if (backoff < 100) - backoff += 10; - return; - } - if (cb) cb(er) - }) - }})(fs.rename) - } +const wrapAnsi16m = (fn, offset) => function () { + const rgb = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; +}; - // if read() returns EAGAIN, then just try it again. - fs.read = (function (fs$read) { - function read (fd, buffer, offset, length, position, callback_) { - var callback - if (callback_ && typeof callback_ === 'function') { - var eagCounter = 0 - callback = function (er, _, __) { - if (er && er.code === 'EAGAIN' && eagCounter < 10) { - eagCounter ++ - return fs$read.call(fs, fd, buffer, offset, length, position, callback) - } - callback_.apply(this, arguments) - } - } - return fs$read.call(fs, fd, buffer, offset, length, position, callback) - } +function assembleStyles() { + const codes = new Map(); + const styles = { + modifier: { + reset: [0, 0], + // 21 isn't widely supported and 22 does the same thing + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29] + }, + color: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + gray: [90, 39], - // This ensures `util.promisify` works as it does for native `fs.read`. - read.__proto__ = fs$read - return read - })(fs.read) + // Bright color + redBright: [91, 39], + greenBright: [92, 39], + yellowBright: [93, 39], + blueBright: [94, 39], + magentaBright: [95, 39], + cyanBright: [96, 39], + whiteBright: [97, 39] + }, + bgColor: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], - fs.readSync = (function (fs$readSync) { return function (fd, buffer, offset, length, position) { - var eagCounter = 0 - while (true) { - try { - return fs$readSync.call(fs, fd, buffer, offset, length, position) - } catch (er) { - if (er.code === 'EAGAIN' && eagCounter < 10) { - eagCounter ++ - continue - } - throw er - } - } - }})(fs.readSync) + // Bright color + bgBlackBright: [100, 49], + bgRedBright: [101, 49], + bgGreenBright: [102, 49], + bgYellowBright: [103, 49], + bgBlueBright: [104, 49], + bgMagentaBright: [105, 49], + bgCyanBright: [106, 49], + bgWhiteBright: [107, 49] + } + }; - function patchLchmod (fs) { - fs.lchmod = function (path, mode, callback) { - fs.open( path - , constants.O_WRONLY | constants.O_SYMLINK - , mode - , function (err, fd) { - if (err) { - if (callback) callback(err) - return - } - // prefer to return the chmod error, if one occurs, - // but still try to close, and report closing errors if they occur. - fs.fchmod(fd, mode, function (err) { - fs.close(fd, function(err2) { - if (callback) callback(err || err2) - }) - }) - }) - } + // Fix humans + styles.color.grey = styles.color.gray; - fs.lchmodSync = function (path, mode) { - var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) + for (const groupName of Object.keys(styles)) { + const group = styles[groupName]; - // prefer to return the chmod error, if one occurs, - // but still try to close, and report closing errors if they occur. - var threw = true - var ret - try { - ret = fs.fchmodSync(fd, mode) - threw = false - } finally { - if (threw) { - try { - fs.closeSync(fd) - } catch (er) {} - } else { - fs.closeSync(fd) - } - } - return ret - } - } + for (const styleName of Object.keys(group)) { + const style = group[styleName]; - function patchLutimes (fs) { - if (constants.hasOwnProperty("O_SYMLINK")) { - fs.lutimes = function (path, at, mt, cb) { - fs.open(path, constants.O_SYMLINK, function (er, fd) { - if (er) { - if (cb) cb(er) - return - } - fs.futimes(fd, at, mt, function (er) { - fs.close(fd, function (er2) { - if (cb) cb(er || er2) - }) - }) - }) - } + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m` + }; - fs.lutimesSync = function (path, at, mt) { - var fd = fs.openSync(path, constants.O_SYMLINK) - var ret - var threw = true - try { - ret = fs.futimesSync(fd, at, mt) - threw = false - } finally { - if (threw) { - try { - fs.closeSync(fd) - } catch (er) {} - } else { - fs.closeSync(fd) - } - } - return ret - } + group[styleName] = styles[styleName]; - } else { - fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) } - fs.lutimesSync = function () {} - } - } + codes.set(style[0], style[1]); + } - function chmodFix (orig) { - if (!orig) return orig - return function (target, mode, cb) { - return orig.call(fs, target, mode, function (er) { - if (chownErOk(er)) er = null - if (cb) cb.apply(this, arguments) - }) - } - } + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false + }); - function chmodFixSync (orig) { - if (!orig) return orig - return function (target, mode) { - try { - return orig.call(fs, target, mode) - } catch (er) { - if (!chownErOk(er)) throw er - } - } - } + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false + }); + } + const ansi2ansi = n => n; + const rgb2rgb = (r, g, b) => [r, g, b]; - function chownFix (orig) { - if (!orig) return orig - return function (target, uid, gid, cb) { - return orig.call(fs, target, uid, gid, function (er) { - if (chownErOk(er)) er = null - if (cb) cb.apply(this, arguments) - }) - } - } + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; - function chownFixSync (orig) { - if (!orig) return orig - return function (target, uid, gid) { - try { - return orig.call(fs, target, uid, gid) - } catch (er) { - if (!chownErOk(er)) throw er - } - } - } + styles.color.ansi = { + ansi: wrapAnsi16(ansi2ansi, 0) + }; + styles.color.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 0) + }; + styles.color.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 0) + }; - function statFix (orig) { - if (!orig) return orig - // Older versions of Node erroneously returned signed integers for - // uid + gid. - return function (target, options, cb) { - if (typeof options === 'function') { - cb = options - options = null - } - function callback (er, stats) { - if (stats) { - if (stats.uid < 0) stats.uid += 0x100000000 - if (stats.gid < 0) stats.gid += 0x100000000 - } - if (cb) cb.apply(this, arguments) - } - return options ? orig.call(fs, target, options, callback) - : orig.call(fs, target, callback) - } - } + styles.bgColor.ansi = { + ansi: wrapAnsi16(ansi2ansi, 10) + }; + styles.bgColor.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 10) + }; + styles.bgColor.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 10) + }; - function statFixSync (orig) { - if (!orig) return orig - // Older versions of Node erroneously returned signed integers for - // uid + gid. - return function (target, options) { - var stats = options ? orig.call(fs, target, options) - : orig.call(fs, target) - if (stats.uid < 0) stats.uid += 0x100000000 - if (stats.gid < 0) stats.gid += 0x100000000 - return stats; - } - } + for (let key of Object.keys(colorConvert)) { + if (typeof colorConvert[key] !== 'object') { + continue; + } - // ENOSYS means that the fs doesn't support the op. Just ignore - // that, because it doesn't matter. - // - // if there's no getuid, or if getuid() is something other - // than 0, and the error is EINVAL or EPERM, then just ignore - // it. - // - // This specific case is a silent failure in cp, install, tar, - // and most other unix tools that manage permissions. - // - // When running as root, or if other types of errors are - // encountered, then it's strict. - function chownErOk (er) { - if (!er) - return true + const suite = colorConvert[key]; - if (er.code === "ENOSYS") - return true + if (key === 'ansi16') { + key = 'ansi'; + } - var nonroot = !process.getuid || process.getuid() !== 0 - if (nonroot) { - if (er.code === "EINVAL" || er.code === "EPERM") - return true - } + if ('ansi16' in suite) { + styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); + styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); + } - return false - } + if ('ansi256' in suite) { + styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); + styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); + } + + if ('rgb' in suite) { + styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); + styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); + } + } + + return styles; } +// Make the export immutable +Object.defineProperty(module, 'exports', { + enumerable: true, + get: assembleStyles +}); + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 666 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { -var Stream = __webpack_require__(27).Stream - -module.exports = legacy - -function legacy (fs) { - return { - ReadStream: ReadStream, - WriteStream: WriteStream - } +"use strict"; - function ReadStream (path, options) { - if (!(this instanceof ReadStream)) return new ReadStream(path, options); +const os = __webpack_require__(11); +const hasFlag = __webpack_require__(12); - Stream.call(this); +const env = process.env; - var self = this; +let forceColor; +if (hasFlag('no-color') || + hasFlag('no-colors') || + hasFlag('color=false')) { + forceColor = false; +} else if (hasFlag('color') || + hasFlag('colors') || + hasFlag('color=true') || + hasFlag('color=always')) { + forceColor = true; +} +if ('FORCE_COLOR' in env) { + forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0; +} - this.path = path; - this.fd = null; - this.readable = true; - this.paused = false; +function translateLevel(level) { + if (level === 0) { + return false; + } - this.flags = 'r'; - this.mode = 438; /*=0666*/ - this.bufferSize = 64 * 1024; + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3 + }; +} - options = options || {}; +function supportsColor(stream) { + if (forceColor === false) { + return 0; + } - // Mixin options into this - var keys = Object.keys(options); - for (var index = 0, length = keys.length; index < length; index++) { - var key = keys[index]; - this[key] = options[key]; - } + if (hasFlag('color=16m') || + hasFlag('color=full') || + hasFlag('color=truecolor')) { + return 3; + } - if (this.encoding) this.setEncoding(this.encoding); + if (hasFlag('color=256')) { + return 2; + } - if (this.start !== undefined) { - if ('number' !== typeof this.start) { - throw TypeError('start must be a Number'); - } - if (this.end === undefined) { - this.end = Infinity; - } else if ('number' !== typeof this.end) { - throw TypeError('end must be a Number'); - } + if (stream && !stream.isTTY && forceColor !== true) { + // VS code debugger doesn't have isTTY set + if (env.VSCODE_PID) { + return 1; + } + return 0; + } - if (this.start > this.end) { - throw new Error('start must be <= end'); - } + const min = forceColor ? 1 : 0; - this.pos = this.start; - } + if (process.platform === 'win32') { + // Node.js 7.5.0 is the first version of Node.js to include a patch to + // libuv that enables 256 color output on Windows. Anything earlier and it + // won't work. However, here we target Node.js 8 at minimum as it is an LTS + // release, and Node.js 7 is not. Windows 10 build 10586 is the first Windows + // release that supports 256 colors. Windows 10 build 14931 is the first release + // that supports 16m/TrueColor. + const osRelease = os.release().split('.'); + if ( + Number(process.versions.node.split('.')[0]) >= 8 && + Number(osRelease[0]) >= 10 && + Number(osRelease[2]) >= 10586 + ) { + return Number(osRelease[2]) >= 14931 ? 3 : 2; + } - if (this.fd !== null) { - process.nextTick(function() { - self._read(); - }); - return; - } + return 1; + } - fs.open(this.path, this.flags, this.mode, function (err, fd) { - if (err) { - self.emit('error', err); - self.readable = false; - return; - } + if ('CI' in env) { + if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { + return 1; + } - self.fd = fd; - self.emit('open', fd); - self._read(); - }) - } + return min; + } - function WriteStream (path, options) { - if (!(this instanceof WriteStream)) return new WriteStream(path, options); + if ('TEAMCITY_VERSION' in env) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + } - Stream.call(this); + if (env.COLORTERM === 'truecolor') { + return 3; + } - this.path = path; - this.fd = null; - this.writable = true; + if ('TERM_PROGRAM' in env) { + const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); - this.flags = 'w'; - this.encoding = 'binary'; - this.mode = 438; /*=0666*/ - this.bytesWritten = 0; + switch (env.TERM_PROGRAM) { + case 'iTerm.app': + return version >= 3 ? 3 : 2; + case 'Apple_Terminal': + return 2; + // No default + } + } - options = options || {}; + if (/-256(color)?$/i.test(env.TERM)) { + return 2; + } - // Mixin options into this - var keys = Object.keys(options); - for (var index = 0, length = keys.length; index < length; index++) { - var key = keys[index]; - this[key] = options[key]; - } + if (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + return 1; + } - if (this.start !== undefined) { - if ('number' !== typeof this.start) { - throw TypeError('start must be a Number'); - } - if (this.start < 0) { - throw new Error('start must be >= zero'); - } + if ('COLORTERM' in env) { + return 1; + } - this.pos = this.start; - } + if (env.TERM === 'dumb') { + return min; + } - this.busy = false; - this._queue = []; + return min; +} - if (this.fd === null) { - this._open = fs.open; - this._queue.push([this._open, this.path, this.flags, this.mode, undefined]); - this.flush(); - } - } +function getSupportLevel(stream) { + const level = supportsColor(stream); + return translateLevel(level); } +module.exports = { + supportsColor: getSupportLevel, + stdout: getSupportLevel(process.stdout), + stderr: getSupportLevel(process.stderr) +}; + /***/ }), -/* 667 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; +const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; +const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; +const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; -module.exports = clone +const ESCAPES = new Map([ + ['n', '\n'], + ['r', '\r'], + ['t', '\t'], + ['b', '\b'], + ['f', '\f'], + ['v', '\v'], + ['0', '\0'], + ['\\', '\\'], + ['e', '\u001B'], + ['a', '\u0007'] +]); -function clone (obj) { - if (obj === null || typeof obj !== 'object') - return obj +function unescape(c) { + if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { + return String.fromCharCode(parseInt(c.slice(1), 16)); + } - if (obj instanceof Object) - var copy = { __proto__: obj.__proto__ } - else - var copy = Object.create(null) + return ESCAPES.get(c) || c; +} - Object.getOwnPropertyNames(obj).forEach(function (key) { - Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key)) - }) +function parseArguments(name, args) { + const results = []; + const chunks = args.trim().split(/\s*,\s*/g); + let matches; - return copy + for (const chunk of chunks) { + if (!isNaN(chunk)) { + results.push(Number(chunk)); + } else if ((matches = chunk.match(STRING_REGEX))) { + results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); + } else { + throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); + } + } + + return results; } +function parseStyle(style) { + STYLE_REGEX.lastIndex = 0; -/***/ }), -/* 668 */ -/***/ (function(module, exports, __webpack_require__) { + const results = []; + let matches; -"use strict"; + while ((matches = STYLE_REGEX.exec(style)) !== null) { + const name = matches[1]; -const path = __webpack_require__(16); + if (matches[2]) { + const args = parseArguments(name, matches[2]); + results.push([name].concat(args)); + } else { + results.push([name]); + } + } -module.exports = path_ => { - let cwd = process.cwd(); + return results; +} - path_ = path.resolve(path_); +function buildStyle(chalk, styles) { + const enabled = {}; - if (process.platform === 'win32') { - cwd = cwd.toLowerCase(); - path_ = path_.toLowerCase(); + for (const layer of styles) { + for (const style of layer.styles) { + enabled[style[0]] = layer.inverse ? null : style.slice(1); + } } - return path_ === cwd; + let current = chalk; + for (const styleName of Object.keys(enabled)) { + if (Array.isArray(enabled[styleName])) { + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); + } + + if (enabled[styleName].length > 0) { + current = current[styleName].apply(current, enabled[styleName]); + } else { + current = current[styleName]; + } + } + } + + return current; +} + +module.exports = (chalk, tmp) => { + const styles = []; + const chunks = []; + let chunk = []; + + // eslint-disable-next-line max-params + tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { + if (escapeChar) { + chunk.push(unescape(escapeChar)); + } else if (style) { + const str = chunk.join(''); + chunk = []; + chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); + styles.push({inverse, styles: parseStyle(style)}); + } else if (close) { + if (styles.length === 0) { + throw new Error('Found extraneous } in Chalk template literal'); + } + + chunks.push(buildStyle(chalk, styles)(chunk.join(''))); + chunk = []; + styles.pop(); + } else { + chunk.push(chr); + } + }); + + chunks.push(chunk.join('')); + + if (styles.length > 0) { + const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; + throw new Error(errMsg); + } + + return chunks.join(''); }; /***/ }), -/* 669 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const path = __webpack_require__(16); +const restoreCursor = __webpack_require__(682); -module.exports = (childPath, parentPath) => { - childPath = path.resolve(childPath); - parentPath = path.resolve(parentPath); +let hidden = false; - if (process.platform === 'win32') { - childPath = childPath.toLowerCase(); - parentPath = parentPath.toLowerCase(); +exports.show = stream => { + const s = stream || process.stderr; + + if (!s.isTTY) { + return; } - if (childPath === parentPath) { - return false; + hidden = false; + s.write('\u001b[?25h'); +}; + +exports.hide = stream => { + const s = stream || process.stderr; + + if (!s.isTTY) { + return; } - childPath += path.sep; - parentPath += path.sep; + restoreCursor(); + hidden = true; + s.write('\u001b[?25l'); +}; - return childPath.startsWith(parentPath); +exports.toggle = (force, stream) => { + if (force !== undefined) { + hidden = force; + } + + if (hidden) { + exports.show(stream); + } else { + exports.hide(stream); + } }; /***/ }), -/* 670 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { -const assert = __webpack_require__(30) -const path = __webpack_require__(16) -const fs = __webpack_require__(23) -let glob = undefined -try { - glob = __webpack_require__(502) -} catch (_err) { - // treat glob as optional. -} +"use strict"; -const defaultGlobOpts = { - nosort: true, - silent: true -} +const onetime = __webpack_require__(683); +const signalExit = __webpack_require__(377); -// for EMFILE handling -let timeout = 0 +module.exports = onetime(() => { + signalExit(() => { + process.stderr.write('\u001b[?25h'); + }, {alwaysLast: true}); +}); -const isWindows = (process.platform === "win32") -const defaults = options => { - const methods = [ - 'unlink', - 'chmod', - 'stat', - 'lstat', - 'rmdir', - 'readdir' - ] - methods.forEach(m => { - options[m] = options[m] || fs[m] - m = m + 'Sync' - options[m] = options[m] || fs[m] - }) +/***/ }), +/* 683 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const mimicFn = __webpack_require__(684); + +module.exports = (fn, opts) => { + // TODO: Remove this in v3 + if (opts === true) { + throw new TypeError('The second argument is now an options object'); + } + + if (typeof fn !== 'function') { + throw new TypeError('Expected a function'); + } + + opts = opts || {}; + + let ret; + let called = false; + const fnName = fn.displayName || fn.name || ''; - options.maxBusyTries = options.maxBusyTries || 3 - options.emfileWait = options.emfileWait || 1000 - if (options.glob === false) { - options.disableGlob = true - } - if (options.disableGlob !== true && glob === undefined) { - throw Error('glob dependency not found, set `options.disableGlob = true` if intentional') - } - options.disableGlob = options.disableGlob || false - options.glob = options.glob || defaultGlobOpts -} + const onetime = function () { + if (called) { + if (opts.throw === true) { + throw new Error(`Function \`${fnName}\` can only be called once`); + } -const rimraf = (p, options, cb) => { - if (typeof options === 'function') { - cb = options - options = {} - } + return ret; + } - assert(p, 'rimraf: missing path') - assert.equal(typeof p, 'string', 'rimraf: path should be a string') - assert.equal(typeof cb, 'function', 'rimraf: callback function required') - assert(options, 'rimraf: invalid options argument provided') - assert.equal(typeof options, 'object', 'rimraf: options should be object') + called = true; + ret = fn.apply(this, arguments); + fn = null; - defaults(options) + return ret; + }; - let busyTries = 0 - let errState = null - let n = 0 + mimicFn(onetime, fn); - const next = (er) => { - errState = errState || er - if (--n === 0) - cb(errState) - } + return onetime; +}; - const afterGlob = (er, results) => { - if (er) - return cb(er) - n = results.length - if (n === 0) - return cb() +/***/ }), +/* 684 */ +/***/ (function(module, exports, __webpack_require__) { - results.forEach(p => { - const CB = (er) => { - if (er) { - if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && - busyTries < options.maxBusyTries) { - busyTries ++ - // try again, with the same exact callback as this one. - return setTimeout(() => rimraf_(p, options, CB), busyTries * 100) - } +"use strict"; - // this one won't happen if graceful-fs is used. - if (er.code === "EMFILE" && timeout < options.emfileWait) { - return setTimeout(() => rimraf_(p, options, CB), timeout ++) - } +module.exports = (to, from) => { + // TODO: use `Reflect.ownKeys()` when targeting Node.js 6 + for (const prop of Object.getOwnPropertyNames(from).concat(Object.getOwnPropertySymbols(from))) { + Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); + } - // already gone - if (er.code === "ENOENT") er = null - } + return to; +}; - timeout = 0 - next(er) - } - rimraf_(p, options, CB) - }) - } - if (options.disableGlob || !glob.hasMagic(p)) - return afterGlob(null, [p]) +/***/ }), +/* 685 */ +/***/ (function(module, exports, __webpack_require__) { - options.lstat(p, (er, stat) => { - if (!er) - return afterGlob(null, [p]) +"use strict"; - glob(p, options.glob, afterGlob) - }) +module.exports = __webpack_require__(686); -} -// Two possible strategies. -// 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR -// 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR -// -// Both result in an extra syscall when you guess wrong. However, there -// are likely far more normal files in the world than directories. This -// is based on the assumption that a the average number of files per -// directory is >= 1. -// -// If anyone ever complains about this, then I guess the strategy could -// be made configurable somehow. But until then, YAGNI. -const rimraf_ = (p, options, cb) => { - assert(p) - assert(options) - assert(typeof cb === 'function') +/***/ }), +/* 686 */ +/***/ (function(module) { - // sunos lets the root user unlink directories, which is... weird. - // so we have to lstat here and make sure it's not a dir. - options.lstat(p, (er, st) => { - if (er && er.code === "ENOENT") - return cb(null) +module.exports = JSON.parse("{\"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\":[\"🌲\",\"🎄\"]}}"); - // Windows can EPERM on stat. Life is suffering. - if (er && er.code === "EPERM" && isWindows) - fixWinEPERM(p, options, er, cb) +/***/ }), +/* 687 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (st && st.isDirectory()) - return rmdir(p, options, er, cb) +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RunCommand", function() { return RunCommand; }); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34); +/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(500); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(501); +/* + * 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. + */ - options.unlink(p, er => { - if (er) { - if (er.code === "ENOENT") - return cb(null) - if (er.code === "EPERM") - return (isWindows) - ? fixWinEPERM(p, options, er, cb) - : rmdir(p, options, er, cb) - if (er.code === "EISDIR") - return rmdir(p, options, er, cb) - } - return cb(er) - }) - }) -} -const fixWinEPERM = (p, options, er, cb) => { - assert(p) - assert(options) - assert(typeof cb === 'function') - if (er) - assert(er instanceof Error) - options.chmod(p, 0o666, er2 => { - if (er2) - cb(er2.code === "ENOENT" ? null : er) - else - options.stat(p, (er3, stats) => { - if (er3) - cb(er3.code === "ENOENT" ? null : er) - else if (stats.isDirectory()) - rmdir(p, options, er, cb) - else - options.unlink(p, cb) - }) - }) -} -const fixWinEPERMSync = (p, options, er) => { - assert(p) - assert(options) - if (er) - assert(er instanceof Error) +const RunCommand = { + description: 'Run script defined in package.json in each package that contains that script.', + name: 'run', - try { - options.chmodSync(p, 0o666) - } catch (er2) { - if (er2.code === "ENOENT") - return - else - throw er - } + async run(projects, projectGraph, { + extraArgs + }) { + const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projects, projectGraph); - let stats - try { - stats = options.statSync(p) - } catch (er3) { - if (er3.code === "ENOENT") - return - else - throw er + if (extraArgs.length === 0) { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.red.bold('\nNo script specified')); + process.exit(1); + } + + const scriptName = extraArgs[0]; + const scriptArgs = extraArgs.slice(1); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`\nRunning script [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(scriptName)}] in batched topological order\n`)); + await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async pkg => { + if (pkg.hasScript(scriptName)) { + await pkg.runScriptStreaming(scriptName, scriptArgs); + } + }); } - if (stats.isDirectory()) - rmdirSync(p, options, er) - else - options.unlinkSync(p) -} +}; -const rmdir = (p, options, originalEr, cb) => { - assert(p) - assert(options) - if (originalEr) - assert(originalEr instanceof Error) - assert(typeof cb === 'function') +/***/ }), +/* 688 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS) - // if we guessed wrong, and it's not a directory, then - // raise the original error. - options.rmdir(p, er => { - if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")) - rmkids(p, options, cb) - else if (er && er.code === "ENOTDIR") - cb(originalEr) - else - cb(er) - }) -} +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WatchCommand", function() { return WatchCommand; }); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34); +/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(500); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(501); +/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(689); +/* + * 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 rmkids = (p, options, cb) => { - assert(p) - assert(options) - assert(typeof cb === 'function') - options.readdir(p, (er, files) => { - if (er) - return cb(er) - let n = files.length - if (n === 0) - return options.rmdir(p, cb) - let errState - files.forEach(f => { - rimraf(path.join(p, f), options, er => { - if (errState) - return - if (er) - return cb(errState = er) - if (--n === 0) - options.rmdir(p, cb) - }) - }) - }) -} -// this looks simpler, and is strictly *faster*, but will -// tie up the JavaScript thread and fail on excessively -// deep directory trees. -const rimrafSync = (p, options) => { - options = options || {} - defaults(options) - assert(p, 'rimraf: missing path') - assert.equal(typeof p, 'string', 'rimraf: path should be a string') - assert(options, 'rimraf: missing options') - assert.equal(typeof options, 'object', 'rimraf: options should be object') - let results - if (options.disableGlob || !glob.hasMagic(p)) { - results = [p] - } else { - try { - options.lstatSync(p) - results = [p] - } catch (er) { - results = glob.sync(p, options.glob) - } - } +/** + * Name of the script in the package/project package.json file to run during `kbn watch`. + */ +const watchScriptName = 'kbn:watch'; +/** + * Name of the Kibana project. + */ - if (!results.length) - return +const kibanaProjectName = 'kibana'; +/** + * Command that traverses through list of available projects/packages that have `kbn:watch` script in their + * package.json files, groups them into topology aware batches and then processes theses batches one by one + * running `kbn:watch` scripts in parallel within the same batch. + * + * Command internally relies on the fact that most of the build systems that are triggered by `kbn:watch` + * will emit special "marker" once build/watch process is ready that we can use as completion condition for + * the `kbn:watch` script and eventually for the entire batch. Currently we support completion "markers" for + * `webpack` and `tsc` only, for the rest we rely on predefined timeouts. + */ - for (let i = 0; i < results.length; i++) { - const p = results[i] +const WatchCommand = { + description: 'Runs `kbn:watch` script for every project.', + name: 'watch', - let st - try { - st = options.lstatSync(p) - } catch (er) { - if (er.code === "ENOENT") - return + async run(projects, projectGraph) { + const projectsToWatch = new Map(); - // Windows can EPERM on stat. Life is suffering. - if (er.code === "EPERM" && isWindows) - fixWinEPERMSync(p, options, er) + for (const project of projects.values()) { + // We can't watch project that doesn't have `kbn:watch` script. + if (project.hasScript(watchScriptName)) { + projectsToWatch.set(project.name, project); + } } - try { - // sunos lets the root user unlink directories, which is... weird. - if (st && st.isDirectory()) - rmdirSync(p, options, null) - else - options.unlinkSync(p) - } catch (er) { - if (er.code === "ENOENT") - return - if (er.code === "EPERM") - return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er) - if (er.code !== "EISDIR") - throw er - - rmdirSync(p, options, er) + if (projectsToWatch.size === 0) { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.red(`\nThere are no projects to watch found. Make sure that projects define 'kbn:watch' script in 'package.json'.\n`)); + return; } - } -} - -const rmdirSync = (p, options, originalEr) => { - assert(p) - assert(options) - if (originalEr) - assert(originalEr instanceof Error) - try { - options.rmdirSync(p) - } catch (er) { - if (er.code === "ENOENT") - return - if (er.code === "ENOTDIR") - throw originalEr - if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM") - rmkidsSync(p, options) - } -} + const projectNames = Array.from(projectsToWatch.keys()); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(`Running ${watchScriptName} scripts for [${projectNames.join(', ')}].`))); // Kibana should always be run the last, so we don't rely on automatic + // topological batching and push it to the last one-entry batch manually. -const rmkidsSync = (p, options) => { - assert(p) - assert(options) - options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options)) + const shouldWatchKibanaProject = projectsToWatch.delete(kibanaProjectName); + const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projectsToWatch, projectGraph); - // We only end up here once we got ENOTEMPTY at least once, and - // at this point, we are guaranteed to have removed all the kids. - // So, we know that it won't be ENOENT or ENOTDIR or anything else. - // try really hard to delete stuff on windows, because it has a - // PROFOUNDLY annoying habit of not closing handles promptly when - // files are deleted, resulting in spurious ENOTEMPTY errors. - const retries = isWindows ? 100 : 1 - let i = 0 - do { - let threw = true - try { - const ret = options.rmdirSync(p, options) - threw = false - return ret - } finally { - if (++i < retries && threw) - continue + if (shouldWatchKibanaProject) { + batchedProjects.push([projects.get(kibanaProjectName)]); } - } while (true) -} -module.exports = rimraf -rimraf.sync = rimrafSync + await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async pkg => { + const completionHint = await Object(_utils_watch__WEBPACK_IMPORTED_MODULE_4__["waitUntilWatchIsReady"])(pkg.runScriptStreaming(watchScriptName).stdout); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`[${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(pkg.name)}] Initial build completed (${completionHint}).`)); + }); + } +}; /***/ }), -/* 671 */ -/***/ (function(module, exports, __webpack_require__) { +/* 689 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "waitUntilWatchIsReady", function() { return waitUntilWatchIsReady; }); +/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(392); +/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(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. + */ -const AggregateError = __webpack_require__(672); -module.exports = async ( - iterable, - mapper, - { - concurrency = Infinity, - stopOnError = true - } = {} -) => { - return new Promise((resolve, reject) => { - if (typeof mapper !== 'function') { - throw new TypeError('Mapper function is required'); - } +/** + * Number of milliseconds we wait before we fall back to the default watch handler. + */ - if (!(typeof concurrency === 'number' && concurrency >= 1)) { - throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); - } +const defaultHandlerDelay = 3000; +/** + * If default watch handler is used, then it's the number of milliseconds we wait for + * any build output before we consider watch task ready. + */ - const ret = []; - const errors = []; - const iterator = iterable[Symbol.iterator](); - let isRejected = false; - let isIterableDone = false; - let resolvingCount = 0; - let currentIndex = 0; +const defaultHandlerReadinessTimeout = 2000; +/** + * Describes configurable watch options. + */ + +function getWatchHandlers(buildOutput$, { + handlerDelay = defaultHandlerDelay, + handlerReadinessTimeout = defaultHandlerReadinessTimeout +}) { + const typescriptHandler = buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('$ tsc')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('Compilation complete.')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mapTo"])('tsc')))); + const webpackHandler = buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('$ webpack')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('Chunk Names')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mapTo"])('webpack')))); + const defaultHandler = rxjs__WEBPACK_IMPORTED_MODULE_0__["of"](undefined).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["delay"])(handlerReadinessTimeout), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["timeout"])(handlerDelay), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["catchError"])(() => rxjs__WEBPACK_IMPORTED_MODULE_0__["of"]('timeout'))))); + return [typescriptHandler, webpackHandler, defaultHandler]; +} - const next = () => { - if (isRejected) { - return; - } +function waitUntilWatchIsReady(stream, opts = {}) { + const buildOutput$ = new rxjs__WEBPACK_IMPORTED_MODULE_0__["Subject"](); - const nextItem = iterator.next(); - const i = currentIndex; - currentIndex++; + const onDataListener = data => buildOutput$.next(data.toString('utf-8')); - if (nextItem.done) { - isIterableDone = true; + const onEndListener = () => buildOutput$.complete(); - if (resolvingCount === 0) { - if (!stopOnError && errors.length !== 0) { - reject(new AggregateError(errors)); - } else { - resolve(ret); - } - } + const onErrorListener = e => buildOutput$.error(e); - return; - } + stream.once('end', onEndListener); + stream.once('error', onErrorListener); + stream.on('data', onDataListener); + return rxjs__WEBPACK_IMPORTED_MODULE_0__["race"](getWatchHandlers(buildOutput$, opts)).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mergeMap"])(whenReady => whenReady), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["finalize"])(() => { + stream.removeListener('data', onDataListener); + stream.removeListener('end', onEndListener); + stream.removeListener('error', onErrorListener); + buildOutput$.complete(); + })).toPromise(); +} - resolvingCount++; +/***/ }), +/* 690 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - (async () => { - try { - const element = await nextItem.value; - ret[i] = await mapper(element, i); - resolvingCount--; - next(); - } catch (error) { - if (stopOnError) { - isRejected = true; - reject(error); - } else { - errors.push(error); - resolvingCount--; - next(); - } - } - })(); - }; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runCommand", function() { return runCommand; }); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(691); +/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(indent_string__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(692); +/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(wrap_ansi__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(515); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(34); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(501); +/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(699); +/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(700); +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } - for (let i = 0; i < concurrency; i++) { - next(); +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - if (isIterableDone) { - break; - } - } - }); -}; +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +/* + * 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. + */ -/***/ }), -/* 672 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; -const indentString = __webpack_require__(673); -const cleanStack = __webpack_require__(674); -const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); -class AggregateError extends Error { - constructor(errors) { - if (!Array.isArray(errors)) { - throw new TypeError(`Expected input to be an Array, got ${typeof errors}`); - } - errors = [...errors].map(error => { - if (error instanceof Error) { - return error; - } - if (error !== null && typeof error === 'object') { - // Handle plain error objects with message property and/or possibly other metadata - return Object.assign(new Error(error.message), error); - } - return new Error(error); - }); +async function runCommand(command, config) { + try { + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`Running [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(command.name)}] command from [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.yellow(config.rootPath)}]:\n`)); + const kbn = await _utils_kibana__WEBPACK_IMPORTED_MODULE_7__["Kibana"].loadFrom(config.rootPath); + const projects = kbn.getFilteredProjects({ + skipKibanaPlugins: Boolean(config.options['skip-kibana-plugins']), + ossOnly: Boolean(config.options.oss), + exclude: toArray(config.options.exclude), + include: toArray(config.options.include) + }); - let message = errors - .map(error => { - // The `stack` property is not standardized, so we can't assume it exists - return typeof error.stack === 'string' ? cleanInternalStack(cleanStack(error.stack)) : String(error); - }) - .join('\n'); - message = '\n' + indentString(message, 4); - super(message); + if (projects.size === 0) { + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.red(`There are no projects found. Double check project name(s) in '-i/--include' and '-e/--exclude' filters.\n`)); + return process.exit(1); + } - this.name = 'AggregateError'; + const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_5__["buildProjectGraph"])(projects); + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`Found [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(projects.size.toString())}] projects:\n`)); + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(Object(_utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__["renderProjectsTree"])(config.rootPath, projects)); + await command.run(projects, projectGraph, _objectSpread({}, config, { + kbn + })); + } catch (e) { + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold.red(`\n[${command.name}] failed:\n`)); - Object.defineProperty(this, '_errors', {value: errors}); - } + if (e instanceof _utils_errors__WEBPACK_IMPORTED_MODULE_3__["CliError"]) { + const msg = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.red(`CliError: ${e.message}\n`); + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(wrap_ansi__WEBPACK_IMPORTED_MODULE_2___default()(msg, 80)); + const keys = Object.keys(e.meta); - * [Symbol.iterator]() { - for (const error of this._errors) { - yield error; - } - } + if (keys.length > 0) { + const metaOutput = keys.map(key => { + const value = e.meta[key]; + return `${key}: ${value}`; + }); + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write('Additional debugging info:\n'); + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(indent_string__WEBPACK_IMPORTED_MODULE_1___default()(metaOutput.join('\n'), 3)); + } + } else { + _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(e.stack); + } + + process.exit(1); + } } -module.exports = AggregateError; +function toArray(value) { + if (value == null) { + return []; + } + return Array.isArray(value) ? value : [value]; +} /***/ }), -/* 673 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77778,1043 +79934,754 @@ module.exports = (str, count, opts) => { /***/ }), -/* 674 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const os = __webpack_require__(11); - -const extractPathRegex = /\s+at.*(?:\(|\s)(.*)\)?/; -const pathRegex = /^(?:(?:(?:node|(?:internal\/[\w/]*|.*node_modules\/(?:babel-polyfill|pirates)\/.*)?\w+)\.js:\d+:\d+)|native)/; -const homeDir = os.homedir(); - -module.exports = (stack, options) => { - options = Object.assign({pretty: false}, options); - - return stack.replace(/\\/g, '/') - .split('\n') - .filter(line => { - const pathMatches = line.match(extractPathRegex); - if (pathMatches === null || !pathMatches[1]) { - return true; - } - - const match = pathMatches[1]; - - // Electron - if ( - match.includes('.app/Contents/Resources/electron.asar') || - match.includes('.app/Contents/Resources/default_app.asar') - ) { - return false; - } - - return !pathRegex.test(match); - }) - .filter(line => line.trim() !== '') - .map(line => { - if (options.pretty) { - return line.replace(extractPathRegex, (m, p1) => m.replace(p1, p1.replace(homeDir, '~'))); - } - - return line; - }) - .join('\n'); -}; - - -/***/ }), -/* 675 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(676); -const cliCursor = __webpack_require__(680); -const cliSpinners = __webpack_require__(684); -const logSymbols = __webpack_require__(566); - -class Ora { - constructor(options) { - if (typeof options === 'string') { - options = { - text: options - }; - } - - this.options = Object.assign({ - text: '', - color: 'cyan', - stream: process.stderr - }, options); - - const sp = this.options.spinner; - this.spinner = typeof sp === 'object' ? sp : (process.platform === 'win32' ? cliSpinners.line : (cliSpinners[sp] || cliSpinners.dots)); // eslint-disable-line no-nested-ternary - - if (this.spinner.frames === undefined) { - throw new Error('Spinner must define `frames`'); - } - - this.text = this.options.text; - this.color = this.options.color; - this.interval = this.options.interval || this.spinner.interval || 100; - this.stream = this.options.stream; - this.id = null; - this.frameIndex = 0; - this.enabled = typeof this.options.enabled === 'boolean' ? this.options.enabled : ((this.stream && this.stream.isTTY) && !process.env.CI); - } - frame() { - const frames = this.spinner.frames; - let frame = frames[this.frameIndex]; - - if (this.color) { - frame = chalk[this.color](frame); - } - - this.frameIndex = ++this.frameIndex % frames.length; - - return frame + ' ' + this.text; - } - clear() { - if (!this.enabled) { - return this; - } - - this.stream.clearLine(); - this.stream.cursorTo(0); - - return this; - } - render() { - this.clear(); - this.stream.write(this.frame()); - - return this; - } - start(text) { - if (text) { - this.text = text; - } - - if (!this.enabled || this.id) { - return this; - } - - cliCursor.hide(this.stream); - this.render(); - this.id = setInterval(this.render.bind(this), this.interval); - - return this; - } - stop() { - if (!this.enabled) { - return this; - } - - clearInterval(this.id); - this.id = null; - this.frameIndex = 0; - this.clear(); - cliCursor.show(this.stream); +const stringWidth = __webpack_require__(693); +const stripAnsi = __webpack_require__(697); - return this; - } - succeed(text) { - return this.stopAndPersist({symbol: logSymbols.success, text}); - } - fail(text) { - return this.stopAndPersist({symbol: logSymbols.error, text}); - } - warn(text) { - return this.stopAndPersist({symbol: logSymbols.warning, text}); - } - info(text) { - return this.stopAndPersist({symbol: logSymbols.info, text}); - } - stopAndPersist(options) { - if (!this.enabled) { - return this; - } +const ESCAPES = new Set([ + '\u001B', + '\u009B' +]); - // Legacy argument - // TODO: Deprecate sometime in the future - if (typeof options === 'string') { - options = { - symbol: options - }; - } +const END_CODE = 39; - options = options || {}; +const ESCAPE_CODES = new Map([ + [0, 0], + [1, 22], + [2, 22], + [3, 23], + [4, 24], + [7, 27], + [8, 28], + [9, 29], + [30, 39], + [31, 39], + [32, 39], + [33, 39], + [34, 39], + [35, 39], + [36, 39], + [37, 39], + [90, 39], + [40, 49], + [41, 49], + [42, 49], + [43, 49], + [44, 49], + [45, 49], + [46, 49], + [47, 49] +]); - this.stop(); - this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); +const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`; - return this; - } -} +// Calculate the length of words split on ' ', ignoring +// the extra characters added by ansi escape codes +const wordLengths = str => str.split(' ').map(s => stringWidth(s)); -module.exports = function (opts) { - return new Ora(opts); -}; +// Wrap a long word across multiple rows +// Ansi escape codes do not count towards length +const wrapWord = (rows, word, cols) => { + const arr = Array.from(word); -module.exports.promise = (action, options) => { - if (typeof action.then !== 'function') { - throw new TypeError('Parameter `action` must be a Promise'); - } + let insideEscape = false; + let visible = stringWidth(stripAnsi(rows[rows.length - 1])); - const spinner = new Ora(options); - spinner.start(); + for (const item of arr.entries()) { + const i = item[0]; + const char = item[1]; + const charLength = stringWidth(char); - action.then( - () => { - spinner.succeed(); - }, - () => { - spinner.fail(); + if (visible + charLength <= cols) { + rows[rows.length - 1] += char; + } else { + rows.push(char); + visible = 0; } - ); - - return spinner; -}; - - -/***/ }), -/* 676 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(677); -const stdoutColor = __webpack_require__(678).stdout; - -const template = __webpack_require__(679); - -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); - -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; - -// `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = new Set(['gray']); - -const styles = Object.create(null); - -function applyOptions(obj, options) { - options = options || {}; - - // Detect level if not set manually - const scLevel = stdoutColor ? stdoutColor.level : 0; - obj.level = options.level === undefined ? scLevel : options.level; - obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; -} - -function Chalk(options) { - // We check for this.template here since calling `chalk.constructor()` - // by itself will have a `this` of a previously constructed chalk object - if (!this || !(this instanceof Chalk) || this.template) { - const chalk = {}; - applyOptions(chalk, options); - - chalk.template = function () { - const args = [].slice.call(arguments); - return chalkTag.apply(null, [chalk.template].concat(args)); - }; - - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); - - chalk.template.constructor = Chalk; - - return chalk.template; - } - - applyOptions(this, options); -} - -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; -} - -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); - styles[key] = { - get() { - const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + if (ESCAPES.has(char)) { + insideEscape = true; + } else if (insideEscape && char === 'm') { + insideEscape = false; + continue; } - }; -} - -styles.visible = { - get() { - return build.call(this, this._styles || [], true, 'visible'); - } -}; - -ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); -for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.has(model)) { - continue; - } - - styles[model] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.color.close, - closeRe: ansiStyles.color.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; + + if (insideEscape) { + continue; } - }; -} -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } + visible += charLength; - const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.bgColor.close, - closeRe: ansiStyles.bgColor.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; + if (visible === cols && i < arr.length - 1) { + rows.push(''); + visible = 0; } - }; -} + } -const proto = Object.defineProperties(() => {}, styles); + // It's possible that the last row we copy over is only + // ansi escape characters, handle this edge-case + if (!visible && rows[rows.length - 1].length > 0 && rows.length > 1) { + rows[rows.length - 2] += rows.pop(); + } +}; -function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; +// The wrap-ansi module can be invoked +// in either 'hard' or 'soft' wrap mode +// +// 'hard' will never allow a string to take up more +// than cols characters +// +// 'soft' allows long words to expand past the column length +const exec = (str, cols, opts) => { + const options = opts || {}; - builder._styles = _styles; - builder._empty = _empty; + if (str.trim() === '') { + return options.trim === false ? str : str.trim(); + } - const self = this; + let pre = ''; + let ret = ''; + let escapeCode; - Object.defineProperty(builder, 'level', { - enumerable: true, - get() { - return self.level; - }, - set(level) { - self.level = level; - } - }); + const lengths = wordLengths(str); + const words = str.split(' '); + const rows = ['']; - Object.defineProperty(builder, 'enabled', { - enumerable: true, - get() { - return self.enabled; - }, - set(enabled) { - self.enabled = enabled; - } - }); + for (const item of Array.from(words).entries()) { + const i = item[0]; + const word = item[1]; - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + rows[rows.length - 1] = options.trim === false ? rows[rows.length - 1] : rows[rows.length - 1].trim(); + let rowLength = stringWidth(rows[rows.length - 1]); - // `__proto__` is used because we must return a function, but there is - // no way to create a function with a different prototype - builder.__proto__ = proto; // eslint-disable-line no-proto + if (rowLength || word === '') { + if (rowLength === cols && options.wordWrap === false) { + // If we start with a new word but the current row length equals the length of the columns, add a new row + rows.push(''); + rowLength = 0; + } - return builder; -} + rows[rows.length - 1] += ' '; + rowLength++; + } -function applyStyle() { - // Support varags, but simply cast to string in case there's only one arg - const args = arguments; - const argsLen = args.length; - let str = String(arguments[0]); + // In 'hard' wrap mode, the length of a line is + // never allowed to extend past 'cols' + if (lengths[i] > cols && options.hard) { + if (rowLength) { + rows.push(''); + } + wrapWord(rows, word, cols); + continue; + } - if (argsLen === 0) { - return ''; - } + if (rowLength + lengths[i] > cols && rowLength > 0) { + if (options.wordWrap === false && rowLength < cols) { + wrapWord(rows, word, cols); + continue; + } - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; + rows.push(''); } - } - if (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; - } + if (rowLength + lengths[i] > cols && options.wordWrap === false) { + wrapWord(rows, word, cols); + continue; + } - // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, - // see https://github.com/chalk/chalk/issues/58 - // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. - const originalDim = ansiStyles.dim.open; - if (isSimpleWindowsTerm && this.hasGrey) { - ansiStyles.dim.open = ''; + rows[rows.length - 1] += word; } - for (const code of this._styles.slice().reverse()) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - str = code.open + str.replace(code.closeRe, code.open) + code.close; - - // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS - // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); - } + pre = rows.map(r => options.trim === false ? r : r.trim()).join('\n'); - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; + for (const item of Array.from(pre).entries()) { + const i = item[0]; + const char = item[1]; - return str; -} + ret += char; -function chalkTag(chalk, strings) { - if (!Array.isArray(strings)) { - // If chalk() was called by itself or with a string, - // return the string itself as a string. - return [].slice.call(arguments, 1).join(' '); - } + if (ESCAPES.has(char)) { + const code = parseFloat(/\d[^m]*/.exec(pre.slice(i, i + 4))); + escapeCode = code === END_CODE ? null : code; + } - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[0]]; + const code = ESCAPE_CODES.get(Number(escapeCode)); - for (let i = 1; i < strings.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); + if (escapeCode && code) { + if (pre[i + 1] === '\n') { + ret += wrapAnsi(code); + } else if (char === '\n') { + ret += wrapAnsi(escapeCode); + } + } } - return template(chalk, parts.join('')); -} - -Object.defineProperties(Chalk.prototype, styles); + return ret; +}; -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript +// For each newline, invoke the method separately +module.exports = (str, cols, opts) => { + return String(str) + .normalize() + .split('\n') + .map(line => exec(line, cols, opts)) + .join('\n'); +}; /***/ }), -/* 677 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* WEBPACK VAR INJECTION */(function(module) { -const colorConvert = __webpack_require__(6); -const wrapAnsi16 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${code + offset}m`; -}; +const stripAnsi = __webpack_require__(694); +const isFullwidthCodePoint = __webpack_require__(696); -const wrapAnsi256 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};5;${code}m`; -}; +module.exports = str => { + if (typeof str !== 'string' || str.length === 0) { + return 0; + } -const wrapAnsi16m = (fn, offset) => function () { - const rgb = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; -}; + str = stripAnsi(str); -function assembleStyles() { - const codes = new Map(); - const styles = { - modifier: { - reset: [0, 0], - // 21 isn't widely supported and 22 does the same thing - bold: [1, 22], - dim: [2, 22], - italic: [3, 23], - underline: [4, 24], - inverse: [7, 27], - hidden: [8, 28], - strikethrough: [9, 29] - }, - color: { - black: [30, 39], - red: [31, 39], - green: [32, 39], - yellow: [33, 39], - blue: [34, 39], - magenta: [35, 39], - cyan: [36, 39], - white: [37, 39], - gray: [90, 39], + let width = 0; - // Bright color - redBright: [91, 39], - greenBright: [92, 39], - yellowBright: [93, 39], - blueBright: [94, 39], - magentaBright: [95, 39], - cyanBright: [96, 39], - whiteBright: [97, 39] - }, - bgColor: { - bgBlack: [40, 49], - bgRed: [41, 49], - bgGreen: [42, 49], - bgYellow: [43, 49], - bgBlue: [44, 49], - bgMagenta: [45, 49], - bgCyan: [46, 49], - bgWhite: [47, 49], + for (let i = 0; i < str.length; i++) { + const code = str.codePointAt(i); - // Bright color - bgBlackBright: [100, 49], - bgRedBright: [101, 49], - bgGreenBright: [102, 49], - bgYellowBright: [103, 49], - bgBlueBright: [104, 49], - bgMagentaBright: [105, 49], - bgCyanBright: [106, 49], - bgWhiteBright: [107, 49] + // Ignore control characters + if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) { + continue; } - }; - // Fix humans - styles.color.grey = styles.color.gray; + // Ignore combining characters + if (code >= 0x300 && code <= 0x36F) { + continue; + } - for (const groupName of Object.keys(styles)) { - const group = styles[groupName]; + // Surrogates + if (code > 0xFFFF) { + i++; + } - for (const styleName of Object.keys(group)) { - const style = group[styleName]; + width += isFullwidthCodePoint(code) ? 2 : 1; + } - styles[styleName] = { - open: `\u001B[${style[0]}m`, - close: `\u001B[${style[1]}m` - }; + return width; +}; - group[styleName] = styles[styleName]; - codes.set(style[0], style[1]); - } +/***/ }), +/* 694 */ +/***/ (function(module, exports, __webpack_require__) { - Object.defineProperty(styles, groupName, { - value: group, - enumerable: false - }); +"use strict"; - Object.defineProperty(styles, 'codes', { - value: codes, - enumerable: false - }); - } +const ansiRegex = __webpack_require__(695); - const ansi2ansi = n => n; - const rgb2rgb = (r, g, b) => [r, g, b]; +module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; - styles.color.close = '\u001B[39m'; - styles.bgColor.close = '\u001B[49m'; - styles.color.ansi = { - ansi: wrapAnsi16(ansi2ansi, 0) - }; - styles.color.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 0) - }; - styles.color.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 0) - }; +/***/ }), +/* 695 */ +/***/ (function(module, exports, __webpack_require__) { - styles.bgColor.ansi = { - ansi: wrapAnsi16(ansi2ansi, 10) - }; - styles.bgColor.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 10) - }; - styles.bgColor.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 10) - }; +"use strict"; - for (let key of Object.keys(colorConvert)) { - if (typeof colorConvert[key] !== 'object') { - continue; - } - const suite = colorConvert[key]; +module.exports = () => { + const pattern = [ + '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)', + '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))' + ].join('|'); - if (key === 'ansi16') { - key = 'ansi'; - } + return new RegExp(pattern, 'g'); +}; - if ('ansi16' in suite) { - styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); - styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); - } - if ('ansi256' in suite) { - styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); - styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); - } +/***/ }), +/* 696 */ +/***/ (function(module, exports, __webpack_require__) { - if ('rgb' in suite) { - styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); - styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); - } +"use strict"; + +/* eslint-disable yoda */ +module.exports = x => { + if (Number.isNaN(x)) { + return false; } - return styles; -} + // code points are derived from: + // http://www.unix.org/Public/UNIDATA/EastAsianWidth.txt + if ( + x >= 0x1100 && ( + x <= 0x115f || // Hangul Jamo + x === 0x2329 || // LEFT-POINTING ANGLE BRACKET + x === 0x232a || // RIGHT-POINTING ANGLE BRACKET + // CJK Radicals Supplement .. Enclosed CJK Letters and Months + (0x2e80 <= x && x <= 0x3247 && x !== 0x303f) || + // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A + (0x3250 <= x && x <= 0x4dbf) || + // CJK Unified Ideographs .. Yi Radicals + (0x4e00 <= x && x <= 0xa4c6) || + // Hangul Jamo Extended-A + (0xa960 <= x && x <= 0xa97c) || + // Hangul Syllables + (0xac00 <= x && x <= 0xd7a3) || + // CJK Compatibility Ideographs + (0xf900 <= x && x <= 0xfaff) || + // Vertical Forms + (0xfe10 <= x && x <= 0xfe19) || + // CJK Compatibility Forms .. Small Form Variants + (0xfe30 <= x && x <= 0xfe6b) || + // Halfwidth and Fullwidth Forms + (0xff01 <= x && x <= 0xff60) || + (0xffe0 <= x && x <= 0xffe6) || + // Kana Supplement + (0x1b000 <= x && x <= 0x1b001) || + // Enclosed Ideographic Supplement + (0x1f200 <= x && x <= 0x1f251) || + // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane + (0x20000 <= x && x <= 0x3fffd) + ) + ) { + return true; + } -// Make the export immutable -Object.defineProperty(module, 'exports', { - enumerable: true, - get: assembleStyles -}); + return false; +}; -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 678 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const os = __webpack_require__(11); -const hasFlag = __webpack_require__(12); +const ansiRegex = __webpack_require__(698); -const env = process.env; +module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; -let forceColor; -if (hasFlag('no-color') || - hasFlag('no-colors') || - hasFlag('color=false')) { - forceColor = false; -} else if (hasFlag('color') || - hasFlag('colors') || - hasFlag('color=true') || - hasFlag('color=always')) { - forceColor = true; -} -if ('FORCE_COLOR' in env) { - forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0; -} -function translateLevel(level) { - if (level === 0) { - return false; - } +/***/ }), +/* 698 */ +/***/ (function(module, exports, __webpack_require__) { - return { - level, - hasBasic: true, - has256: level >= 2, - has16m: level >= 3 - }; -} +"use strict"; -function supportsColor(stream) { - if (forceColor === false) { - return 0; - } - if (hasFlag('color=16m') || - hasFlag('color=full') || - hasFlag('color=truecolor')) { - return 3; - } +module.exports = () => { + const pattern = [ + '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)', + '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))' + ].join('|'); - if (hasFlag('color=256')) { - return 2; - } + return new RegExp(pattern, 'g'); +}; + + +/***/ }), +/* 699 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderProjectsTree", function() { return renderProjectsTree; }); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(16); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); +/* + * 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. + */ - if (stream && !stream.isTTY && forceColor !== true) { - // VS code debugger doesn't have isTTY set - if (env.VSCODE_PID) { - return 1; - } - return 0; - } - const min = forceColor ? 1 : 0; +const projectKey = Symbol('__project'); +function renderProjectsTree(rootPath, projects) { + const projectsTree = buildProjectsTree(rootPath, projects); + return treeToString(createTreeStructure(projectsTree)); +} - if (process.platform === 'win32') { - // Node.js 7.5.0 is the first version of Node.js to include a patch to - // libuv that enables 256 color output on Windows. Anything earlier and it - // won't work. However, here we target Node.js 8 at minimum as it is an LTS - // release, and Node.js 7 is not. Windows 10 build 10586 is the first Windows - // release that supports 256 colors. Windows 10 build 14931 is the first release - // that supports 16m/TrueColor. - const osRelease = os.release().split('.'); - if ( - Number(process.versions.node.split('.')[0]) >= 8 && - Number(osRelease[0]) >= 10 && - Number(osRelease[2]) >= 10586 - ) { - return Number(osRelease[2]) >= 14931 ? 3 : 2; - } +function treeToString(tree) { + return [tree.name].concat(childrenToStrings(tree.children, '')).join('\n'); +} - return 1; - } +function childrenToStrings(tree, treePrefix) { + if (tree === undefined) { + return []; + } - if ('CI' in env) { - if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { - return 1; - } + let strings = []; + tree.forEach((node, index) => { + const isLastNode = tree.length - 1 === index; + const nodePrefix = isLastNode ? '└── ' : '├── '; + const childPrefix = isLastNode ? ' ' : '│ '; + const childrenPrefix = treePrefix + childPrefix; + strings.push(`${treePrefix}${nodePrefix}${node.name}`); + strings = strings.concat(childrenToStrings(node.children, childrenPrefix)); + }); + return strings; +} - return min; - } +function createTreeStructure(tree) { + let name; + const children = []; - if ('TEAMCITY_VERSION' in env) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; - } + for (const [dir, project] of tree.entries()) { + // This is a leaf node (aka a project) + if (typeof project === 'string') { + name = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(project); + continue; + } // If there's only one project and the key indicates it's a leaf node, we + // know that we're at a package folder that contains a package.json, so we + // "inline it" so we don't get unnecessary levels, i.e. we'll just see + // `foo` instead of `foo -> foo`. - if (env.COLORTERM === 'truecolor') { - return 3; - } - if ('TERM_PROGRAM' in env) { - const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + if (project.size === 1 && project.has(projectKey)) { + const projectName = project.get(projectKey); + children.push({ + children: [], + name: dirOrProjectName(dir, projectName) + }); + continue; + } - switch (env.TERM_PROGRAM) { - case 'iTerm.app': - return version >= 3 ? 3 : 2; - case 'Apple_Terminal': - return 2; - // No default - } - } + const subtree = createTreeStructure(project); // If the name is specified, we know there's a package at the "root" of the + // subtree itself. - if (/-256(color)?$/i.test(env.TERM)) { - return 2; - } + if (subtree.name !== undefined) { + const projectName = subtree.name; + children.push({ + children: subtree.children, + name: dirOrProjectName(dir, projectName) + }); + continue; + } // Special-case whenever we have one child, so we don't get unnecessary + // folders in the output. E.g. instead of `foo -> bar -> baz` we get + // `foo/bar/baz` instead. - if (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { - return 1; - } - if ('COLORTERM' in env) { - return 1; - } + if (subtree.children && subtree.children.length === 1) { + const child = subtree.children[0]; + const newName = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(path__WEBPACK_IMPORTED_MODULE_1___default.a.join(dir.toString(), child.name)); + children.push({ + children: child.children, + name: newName + }); + continue; + } - if (env.TERM === 'dumb') { - return min; - } + children.push({ + children: subtree.children, + name: chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(dir.toString()) + }); + } - return min; + return { + name, + children + }; } -function getSupportLevel(stream) { - const level = supportsColor(stream); - return translateLevel(level); +function dirOrProjectName(dir, projectName) { + return dir === projectName ? chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(dir) : chalk__WEBPACK_IMPORTED_MODULE_0___default.a`{dim ${dir.toString()} ({reset.green ${projectName}})}`; } -module.exports = { - supportsColor: getSupportLevel, - stdout: getSupportLevel(process.stdout), - stderr: getSupportLevel(process.stderr) -}; - - -/***/ }), -/* 679 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; -const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; -const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; -const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; - -const ESCAPES = new Map([ - ['n', '\n'], - ['r', '\r'], - ['t', '\t'], - ['b', '\b'], - ['f', '\f'], - ['v', '\v'], - ['0', '\0'], - ['\\', '\\'], - ['e', '\u001B'], - ['a', '\u0007'] -]); +function buildProjectsTree(rootPath, projects) { + const tree = new Map(); -function unescape(c) { - if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { - return String.fromCharCode(parseInt(c.slice(1), 16)); - } + for (const project of projects.values()) { + if (rootPath === project.path) { + tree.set(projectKey, project.name); + } else { + const relativeProjectPath = path__WEBPACK_IMPORTED_MODULE_1___default.a.relative(rootPath, project.path); + addProjectToTree(tree, relativeProjectPath.split(path__WEBPACK_IMPORTED_MODULE_1___default.a.sep), project); + } + } - return ESCAPES.get(c) || c; + return tree; } -function parseArguments(name, args) { - const results = []; - const chunks = args.trim().split(/\s*,\s*/g); - let matches; +function addProjectToTree(tree, pathParts, project) { + if (pathParts.length === 0) { + tree.set(projectKey, project.name); + } else { + const [currentDir, ...rest] = pathParts; - for (const chunk of chunks) { - if (!isNaN(chunk)) { - results.push(Number(chunk)); - } else if ((matches = chunk.match(STRING_REGEX))) { - results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); - } else { - throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); - } - } + if (!tree.has(currentDir)) { + tree.set(currentDir, new Map()); + } - return results; + const subtree = tree.get(currentDir); + addProjectToTree(subtree, rest, project); + } } -function parseStyle(style) { - STYLE_REGEX.lastIndex = 0; +/***/ }), +/* 700 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - const results = []; - let matches; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Kibana", function() { return Kibana; }); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(16); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(701); +/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(501); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(580); +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } - } +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - return results; -} +/* + * 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. + */ -function buildStyle(chalk, styles) { - const enabled = {}; - for (const layer of styles) { - for (const style of layer.styles) { - enabled[style[0]] = layer.inverse ? null : style.slice(1); - } - } - let current = chalk; - for (const styleName of Object.keys(enabled)) { - if (Array.isArray(enabled[styleName])) { - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); - } - if (enabled[styleName].length > 0) { - current = current[styleName].apply(current, enabled[styleName]); - } else { - current = current[styleName]; - } - } - } +/** + * Helper class for dealing with a set of projects as children of + * the Kibana project. The kbn/pm is currently implemented to be + * more generic, where everything is an operation of generic projects, + * but that leads to exceptions where we need the kibana project and + * do things like `project.get('kibana')!`. + * + * Using this helper we can restructre the generic list of projects + * as a Kibana object which encapulates all the projects in the + * workspace and knows about the root Kibana project. + */ - return current; -} +class Kibana { + static async loadFrom(rootPath) { + return new Kibana((await Object(_projects__WEBPACK_IMPORTED_MODULE_2__["getProjects"])(rootPath, Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])({ + rootPath + })))); + } -module.exports = (chalk, tmp) => { - const styles = []; - const chunks = []; - let chunk = []; + constructor(allWorkspaceProjects) { + this.allWorkspaceProjects = allWorkspaceProjects; - // eslint-disable-next-line max-params - tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { - if (escapeChar) { - chunk.push(unescape(escapeChar)); - } else if (style) { - const str = chunk.join(''); - chunk = []; - chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); - styles.push({inverse, styles: parseStyle(style)}); - } else if (close) { - if (styles.length === 0) { - throw new Error('Found extraneous } in Chalk template literal'); - } + _defineProperty(this, "kibanaProject", void 0); - chunks.push(buildStyle(chalk, styles)(chunk.join(''))); - chunk = []; - styles.pop(); - } else { - chunk.push(chr); - } - }); + const kibanaProject = allWorkspaceProjects.get('kibana'); - chunks.push(chunk.join('')); + if (!kibanaProject) { + throw new TypeError('Unable to create Kibana object without all projects, including the Kibana project.'); + } - if (styles.length > 0) { - const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; - throw new Error(errMsg); - } + this.kibanaProject = kibanaProject; + } + /** make an absolute path by resolving subPath relative to the kibana repo */ - return chunks.join(''); -}; + getAbsolute(...subPath) { + return path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(this.kibanaProject.path, ...subPath); + } + /** convert an absolute path to a relative path, relative to the kibana repo */ -/***/ }), -/* 680 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; + getRelative(absolute) { + return path__WEBPACK_IMPORTED_MODULE_0___default.a.relative(this.kibanaProject.path, absolute); + } + /** get a copy of the map of all projects in the kibana workspace */ -const restoreCursor = __webpack_require__(681); -let hidden = false; + getAllProjects() { + return new Map(this.allWorkspaceProjects); + } + /** determine if a project with the given name exists */ -exports.show = stream => { - const s = stream || process.stderr; - if (!s.isTTY) { - return; - } + hasProject(name) { + return this.allWorkspaceProjects.has(name); + } + /** get a specific project, throws if the name is not known (use hasProject() first) */ - hidden = false; - s.write('\u001b[?25h'); -}; -exports.hide = stream => { - const s = stream || process.stderr; + getProject(name) { + const project = this.allWorkspaceProjects.get(name); - if (!s.isTTY) { - return; - } + if (!project) { + throw new Error(`No package with name "${name}" in the workspace`); + } - restoreCursor(); - hidden = true; - s.write('\u001b[?25l'); -}; + return project; + } + /** get a project and all of the projects it depends on in a ProjectMap */ -exports.toggle = (force, stream) => { - if (force !== undefined) { - hidden = force; - } - if (hidden) { - exports.show(stream); - } else { - exports.hide(stream); - } -}; + getProjectAndDeps(name) { + const project = this.getProject(name); + return Object(_projects__WEBPACK_IMPORTED_MODULE_2__["includeTransitiveProjects"])([project], this.allWorkspaceProjects); + } + /** filter the projects to just those matching certain paths/include/exclude tags */ -/***/ }), -/* 681 */ -/***/ (function(module, exports, __webpack_require__) { + getFilteredProjects(options) { + const allProjects = this.getAllProjects(); + const filteredProjects = new Map(); + const pkgJsonPaths = Array.from(allProjects.values()).map(p => p.packageJsonLocation); + const filteredPkgJsonGlobs = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])(_objectSpread({}, options, { + rootPath: this.kibanaProject.path + })).map(g => path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(g, 'package.json')); + const matchingPkgJsonPaths = multimatch__WEBPACK_IMPORTED_MODULE_1___default()(pkgJsonPaths, filteredPkgJsonGlobs); -"use strict"; + for (const project of allProjects.values()) { + const pathMatches = matchingPkgJsonPaths.includes(project.packageJsonLocation); + const notExcluded = !options.exclude.includes(project.name); + const isIncluded = !options.include.length || options.include.includes(project.name); -const onetime = __webpack_require__(682); -const signalExit = __webpack_require__(377); + if (pathMatches && notExcluded && isIncluded) { + filteredProjects.set(project.name, project); + } + } -module.exports = onetime(() => { - signalExit(() => { - process.stderr.write('\u001b[?25h'); - }, {alwaysLast: true}); -}); + return filteredProjects; + } +} /***/ }), -/* 682 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(683); +const minimatch = __webpack_require__(505); +const arrayUnion = __webpack_require__(702); +const arrayDiffer = __webpack_require__(703); +const arrify = __webpack_require__(704); -module.exports = (fn, opts) => { - // TODO: Remove this in v3 - if (opts === true) { - throw new TypeError('The second argument is now an options object'); - } +module.exports = (list, patterns, options = {}) => { + list = arrify(list); + patterns = arrify(patterns); - if (typeof fn !== 'function') { - throw new TypeError('Expected a function'); + if (list.length === 0 || patterns.length === 0) { + return []; } - opts = opts || {}; + return patterns.reduce((result, pattern) => { + let process = arrayUnion; - let ret; - let called = false; - const fnName = fn.displayName || fn.name || ''; + if (pattern[0] === '!') { + pattern = pattern.slice(1); + process = arrayDiffer; + } - const onetime = function () { - if (called) { - if (opts.throw === true) { - throw new Error(`Function \`${fnName}\` can only be called once`); - } + return process(result, minimatch.match(list, pattern, options)); + }, []); +}; - return ret; - } - called = true; - ret = fn.apply(this, arguments); - fn = null; +/***/ }), +/* 702 */ +/***/ (function(module, exports, __webpack_require__) { - return ret; - }; +"use strict"; - mimicFn(onetime, fn); - return onetime; +module.exports = (...arguments_) => { + return [...new Set([].concat(...arguments_))]; }; /***/ }), -/* 683 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = (to, from) => { - // TODO: use `Reflect.ownKeys()` when targeting Node.js 6 - for (const prop of Object.getOwnPropertyNames(from).concat(Object.getOwnPropertySymbols(from))) { - Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); - } - return to; +const arrayDiffer = (array, ...values) => { + const rest = new Set([].concat(...values)); + return array.filter(element => !rest.has(element)); }; +module.exports = arrayDiffer; + /***/ }), -/* 684 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(685); +const arrify = value => { + if (value === null || value === undefined) { + return []; + } -/***/ }), -/* 685 */ -/***/ (function(module) { + if (Array.isArray(value)) { + return value; + } + + if (typeof value === 'string') { + return [value]; + } + + if (typeof value[Symbol.iterator] === 'function') { + return [...value]; + } + + return [value]; +}; + +module.exports = arrify; -module.exports = JSON.parse("{\"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\":[\"🌲\",\"🎄\"]}}"); /***/ }), -/* 686 */ +/* 705 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RunCommand", function() { return RunCommand; }); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34); -/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(500); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(501); +/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); + +/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(923); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); + /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -78836,46 +80703,24 @@ __webpack_require__.r(__webpack_exports__); - -const RunCommand = { - description: 'Run script defined in package.json in each package that contains that script.', - name: 'run', - - async run(projects, projectGraph, { - extraArgs - }) { - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projects, projectGraph); - - if (extraArgs.length === 0) { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.red.bold('\nNo script specified')); - process.exit(1); - } - - const scriptName = extraArgs[0]; - const scriptArgs = extraArgs.slice(1); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`\nRunning script [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(scriptName)}] in batched topological order\n`)); - await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async pkg => { - if (pkg.hasScript(scriptName)) { - await pkg.runScriptStreaming(scriptName, scriptArgs); - } - }); - } - -}; - /***/ }), -/* 687 */ +/* 706 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WatchCommand", function() { return WatchCommand; }); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34); -/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(500); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(501); -/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(688); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; }); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(707); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(588); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(580); +/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34); +/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(517); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(501); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -78900,1532 +80745,2066 @@ __webpack_require__.r(__webpack_exports__); + + +async function buildProductionProjects({ + kibanaRoot, + buildRoot, + onlyOSS +}) { + const projects = await getProductionProjects(kibanaRoot, onlyOSS); + const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["buildProjectGraph"])(projects); + const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["topologicallyBatchProjects"])(projects, projectGraph); + const projectNames = [...projects.values()].map(project => project.name); + _utils_log__WEBPACK_IMPORTED_MODULE_5__["log"].write(`Preparing production build for [${projectNames.join(', ')}]`); + + for (const batch of batchedProjects) { + for (const project of batch) { + await deleteTarget(project); + await buildProject(project); + await copyToBuild(project, kibanaRoot, buildRoot); + } + } +} /** - * Name of the script in the package/project package.json file to run during `kbn watch`. - */ -const watchScriptName = 'kbn:watch'; -/** - * Name of the Kibana project. + * Returns the subset of projects that should be built into the production + * bundle. As we copy these into Kibana's `node_modules` during the build step, + * and let Kibana's build process be responsible for installing dependencies, + * we only include Kibana's transitive _production_ dependencies. If onlyOSS + * is supplied, we omit projects with build.oss in their package.json set to false. */ -const kibanaProjectName = 'kibana'; +async function getProductionProjects(rootPath, onlyOSS) { + const projectPaths = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])({ + rootPath + }); + const projects = await Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["getProjects"])(rootPath, projectPaths); + const projectsSubset = [projects.get('kibana')]; + + if (projects.has('x-pack')) { + projectsSubset.push(projects.get('x-pack')); + } + + const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, { + onlyProductionDependencies: true + }); // We remove Kibana, as we're already building Kibana + + productionProjects.delete('kibana'); + + if (onlyOSS) { + productionProjects.forEach(project => { + if (project.getBuildConfig().oss === false) { + productionProjects.delete(project.json.name); + } + }); + } + + return productionProjects; +} + +async function deleteTarget(project) { + const targetDir = project.targetLocation; + + if (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isDirectory"])(targetDir)) { + await del__WEBPACK_IMPORTED_MODULE_1___default()(targetDir, { + force: true + }); + } +} + +async function buildProject(project) { + if (project.hasScript('build')) { + await project.runScript('build'); + } +} /** - * Command that traverses through list of available projects/packages that have `kbn:watch` script in their - * package.json files, groups them into topology aware batches and then processes theses batches one by one - * running `kbn:watch` scripts in parallel within the same batch. + * Copy all the project's files from its "intermediate build directory" and + * into the build. The intermediate directory can either be the root of the + * project or some other location defined in the project's `package.json`. * - * Command internally relies on the fact that most of the build systems that are triggered by `kbn:watch` - * will emit special "marker" once build/watch process is ready that we can use as completion condition for - * the `kbn:watch` script and eventually for the entire batch. Currently we support completion "markers" for - * `webpack` and `tsc` only, for the rest we rely on predefined timeouts. + * When copying all the files into the build, we exclude `node_modules` because + * we want the Kibana build to be responsible for actually installing all + * dependencies. The primary reason for allowing the Kibana build process to + * manage dependencies is that it will "dedupe" them, so we don't include + * unnecessary copies of dependencies. */ -const WatchCommand = { - description: 'Runs `kbn:watch` script for every project.', - name: 'watch', - async run(projects, projectGraph) { - const projectsToWatch = new Map(); +async function copyToBuild(project, kibanaRoot, buildRoot) { + // We want the package to have the same relative location within the build + const relativeProjectPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["relative"])(kibanaRoot, project.path); + const buildProjectPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(buildRoot, relativeProjectPath); + await cpy__WEBPACK_IMPORTED_MODULE_0___default()(['**/*', '!node_modules/**'], buildProjectPath, { + cwd: project.getIntermediateBuildDirectory(), + dot: true, + nodir: true, + parents: true + }); // If a project is using an intermediate build directory, we special-case our + // handling of `package.json`, as the project build process might have copied + // (a potentially modified) `package.json` into the intermediate build + // directory already. If so, we want to use that `package.json` as the basis + // for creating the production-ready `package.json`. If it's not present in + // the intermediate build, we fall back to using the project's already defined + // `package.json`. - for (const project of projects.values()) { - // We can't watch project that doesn't have `kbn:watch` script. - if (project.hasScript(watchScriptName)) { - projectsToWatch.set(project.name, project); - } - } + const packageJson = (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isFile"])(Object(path__WEBPACK_IMPORTED_MODULE_2__["join"])(buildProjectPath, 'package.json'))) ? await Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_6__["readPackageJson"])(buildProjectPath) : project.json; + await Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_6__["writePackageJson"])(buildProjectPath, packageJson); +} - if (projectsToWatch.size === 0) { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.red(`\nThere are no projects to watch found. Make sure that projects define 'kbn:watch' script in 'package.json'.\n`)); - return; - } +/***/ }), +/* 707 */ +/***/ (function(module, exports, __webpack_require__) { - const projectNames = Array.from(projectsToWatch.keys()); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(`Running ${watchScriptName} scripts for [${projectNames.join(', ')}].`))); // Kibana should always be run the last, so we don't rely on automatic - // topological batching and push it to the last one-entry batch manually. +"use strict"; - const shouldWatchKibanaProject = projectsToWatch.delete(kibanaProjectName); - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projectsToWatch, projectGraph); +const EventEmitter = __webpack_require__(379); +const path = __webpack_require__(16); +const arrify = __webpack_require__(708); +const globby = __webpack_require__(709); +const cpFile = __webpack_require__(912); +const CpyError = __webpack_require__(921); - if (shouldWatchKibanaProject) { - batchedProjects.push([projects.get(kibanaProjectName)]); - } +const preprocessSrcPath = (srcPath, options) => options.cwd ? path.resolve(options.cwd, srcPath) : srcPath; - await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async pkg => { - const completionHint = await Object(_utils_watch__WEBPACK_IMPORTED_MODULE_4__["waitUntilWatchIsReady"])(pkg.runScriptStreaming(watchScriptName).stdout); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`[${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(pkg.name)}] Initial build completed (${completionHint}).`)); - }); - } +const preprocessDestPath = (srcPath, dest, options) => { + let basename = path.basename(srcPath); + const dirname = path.dirname(srcPath); + + if (typeof options.rename === 'string') { + basename = options.rename; + } else if (typeof options.rename === 'function') { + basename = options.rename(basename); + } + + if (options.cwd) { + dest = path.resolve(options.cwd, dest); + } + + if (options.parents) { + return path.join(dest, dirname, basename); + } + + return path.join(dest, basename); +}; + +const cpy = (src, dest, options = {}) => { + src = arrify(src); + + const progressEmitter = new EventEmitter(); + + if (src.length === 0 || !dest) { + const promise = Promise.reject(new CpyError('`files` and `destination` required')); + promise.on = (...args) => { + progressEmitter.on(...args); + return promise; + }; + + return promise; + } + + const copyStatus = new Map(); + let completedFiles = 0; + let completedSize = 0; + + const promise = globby(src, options) + .catch(error => { + throw new CpyError(`Cannot glob \`${src}\`: ${error.message}`, error); + }) + .then(files => { + if (files.length === 0) { + progressEmitter.emit('progress', { + totalFiles: 0, + percent: 1, + completedFiles: 0, + completedSize: 0 + }); + } + + return Promise.all(files.map(srcPath => { + const from = preprocessSrcPath(srcPath, options); + const to = preprocessDestPath(srcPath, dest, options); + + return cpFile(from, to, options) + .on('progress', event => { + const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; + + if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { + completedSize -= fileStatus.written; + completedSize += event.written; + + if (event.percent === 1 && fileStatus.percent !== 1) { + completedFiles++; + } + + copyStatus.set(event.src, {written: event.written, percent: event.percent}); + + progressEmitter.emit('progress', { + totalFiles: files.length, + percent: completedFiles / files.length, + completedFiles, + completedSize + }); + } + }) + .then(() => to) + .catch(error => { + throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); + }); + })); + }); + + promise.on = (...args) => { + progressEmitter.on(...args); + return promise; + }; + return promise; }; +module.exports = cpy; +// TODO: Remove this for the next major release +module.exports.default = cpy; + + /***/ }), -/* 688 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 708 */ +/***/ (function(module, exports, __webpack_require__) { "use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "waitUntilWatchIsReady", function() { return waitUntilWatchIsReady; }); -/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(392); -/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(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. - */ +module.exports = function (val) { + if (val === null || val === undefined) { + return []; + } -/** - * Number of milliseconds we wait before we fall back to the default watch handler. - */ + return Array.isArray(val) ? val : [val]; +}; -const defaultHandlerDelay = 3000; -/** - * If default watch handler is used, then it's the number of milliseconds we wait for - * any build output before we consider watch task ready. - */ -const defaultHandlerReadinessTimeout = 2000; -/** - * Describes configurable watch options. - */ +/***/ }), +/* 709 */ +/***/ (function(module, exports, __webpack_require__) { -function getWatchHandlers(buildOutput$, { - handlerDelay = defaultHandlerDelay, - handlerReadinessTimeout = defaultHandlerReadinessTimeout -}) { - const typescriptHandler = buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('$ tsc')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('Compilation complete.')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mapTo"])('tsc')))); - const webpackHandler = buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('$ webpack')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('Chunk Names')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mapTo"])('webpack')))); - const defaultHandler = rxjs__WEBPACK_IMPORTED_MODULE_0__["of"](undefined).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["delay"])(handlerReadinessTimeout), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["timeout"])(handlerDelay), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["catchError"])(() => rxjs__WEBPACK_IMPORTED_MODULE_0__["of"]('timeout'))))); - return [typescriptHandler, webpackHandler, defaultHandler]; -} +"use strict"; -function waitUntilWatchIsReady(stream, opts = {}) { - const buildOutput$ = new rxjs__WEBPACK_IMPORTED_MODULE_0__["Subject"](); +const fs = __webpack_require__(23); +const arrayUnion = __webpack_require__(710); +const glob = __webpack_require__(712); +const fastGlob = __webpack_require__(717); +const dirGlob = __webpack_require__(905); +const gitignore = __webpack_require__(908); - const onDataListener = data => buildOutput$.next(data.toString('utf-8')); +const DEFAULT_FILTER = () => false; - const onEndListener = () => buildOutput$.complete(); +const isNegative = pattern => pattern[0] === '!'; - const onErrorListener = e => buildOutput$.error(e); +const assertPatternsInput = patterns => { + if (!patterns.every(x => typeof x === 'string')) { + throw new TypeError('Patterns must be a string or an array of strings'); + } +}; + +const checkCwdOption = options => { + if (options && options.cwd && !fs.statSync(options.cwd).isDirectory()) { + throw new Error('The `cwd` option must be a path to a directory'); + } +}; + +const generateGlobTasks = (patterns, taskOptions) => { + patterns = arrayUnion([].concat(patterns)); + assertPatternsInput(patterns); + checkCwdOption(taskOptions); + + const globTasks = []; + + taskOptions = Object.assign({ + ignore: [], + expandDirectories: true + }, taskOptions); + + patterns.forEach((pattern, i) => { + if (isNegative(pattern)) { + return; + } + + const ignore = patterns + .slice(i) + .filter(isNegative) + .map(pattern => pattern.slice(1)); + + const options = Object.assign({}, taskOptions, { + ignore: taskOptions.ignore.concat(ignore) + }); + + globTasks.push({pattern, options}); + }); + + return globTasks; +}; + +const globDirs = (task, fn) => { + let options = {}; + if (task.options.cwd) { + options.cwd = task.options.cwd; + } + + if (Array.isArray(task.options.expandDirectories)) { + options = Object.assign(options, {files: task.options.expandDirectories}); + } else if (typeof task.options.expandDirectories === 'object') { + options = Object.assign(options, task.options.expandDirectories); + } + + return fn(task.pattern, options); +}; + +const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern]; + +const globToTask = task => glob => { + const {options} = task; + if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { + options.ignore = dirGlob.sync(options.ignore); + } + + return { + pattern: glob, + options + }; +}; + +const globby = (patterns, options) => { + let globTasks; + + try { + globTasks = generateGlobTasks(patterns, options); + } catch (error) { + return Promise.reject(error); + } + + const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob)) + .then(globs => Promise.all(globs.map(globToTask(task)))) + )) + .then(tasks => arrayUnion(...tasks)); + + const getFilter = () => { + return Promise.resolve( + options && options.gitignore ? + gitignore({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER + ); + }; + + return getFilter() + .then(filter => { + return getTasks + .then(tasks => Promise.all(tasks.map(task => fastGlob(task.pattern, task.options)))) + .then(paths => arrayUnion(...paths)) + .then(paths => paths.filter(p => !filter(p))); + }); +}; + +module.exports = globby; +// TODO: Remove this for the next major release +module.exports.default = globby; + +module.exports.sync = (patterns, options) => { + const globTasks = generateGlobTasks(patterns, options); + + const getFilter = () => { + return options && options.gitignore ? + gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER; + }; + + const tasks = globTasks.reduce((tasks, task) => { + const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); + return tasks.concat(newTask); + }, []); + + const filter = getFilter(); + return tasks.reduce( + (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), + [] + ).filter(p => !filter(p)); +}; + +module.exports.generateGlobTasks = generateGlobTasks; + +module.exports.hasMagic = (patterns, options) => [] + .concat(patterns) + .some(pattern => glob.hasMagic(pattern, options)); + +module.exports.gitignore = gitignore; - stream.once('end', onEndListener); - stream.once('error', onErrorListener); - stream.on('data', onDataListener); - return rxjs__WEBPACK_IMPORTED_MODULE_0__["race"](getWatchHandlers(buildOutput$, opts)).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mergeMap"])(whenReady => whenReady), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["finalize"])(() => { - stream.removeListener('data', onDataListener); - stream.removeListener('end', onEndListener); - stream.removeListener('error', onErrorListener); - buildOutput$.complete(); - })).toPromise(); -} /***/ }), -/* 689 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 710 */ +/***/ (function(module, exports, __webpack_require__) { "use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runCommand", function() { return runCommand; }); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(673); -/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(indent_string__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(690); -/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(wrap_ansi__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(515); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(34); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(501); -/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(697); -/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(698); -function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +var arrayUniq = __webpack_require__(711); -/* - * 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 = function () { + return arrayUniq([].concat.apply([], arguments)); +}; +/***/ }), +/* 711 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +// there's 3 implementations written in increasing order of efficiency +// 1 - no Set type is defined +function uniqNoSet(arr) { + var ret = []; + for (var i = 0; i < arr.length; i++) { + if (ret.indexOf(arr[i]) === -1) { + ret.push(arr[i]); + } + } -async function runCommand(command, config) { - try { - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`Running [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(command.name)}] command from [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.yellow(config.rootPath)}]:\n`)); - const kbn = await _utils_kibana__WEBPACK_IMPORTED_MODULE_7__["Kibana"].loadFrom(config.rootPath); - const projects = kbn.getFilteredProjects({ - skipKibanaPlugins: Boolean(config.options['skip-kibana-plugins']), - ossOnly: Boolean(config.options.oss), - exclude: toArray(config.options.exclude), - include: toArray(config.options.include) - }); + return ret; +} - if (projects.size === 0) { - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.red(`There are no projects found. Double check project name(s) in '-i/--include' and '-e/--exclude' filters.\n`)); - return process.exit(1); - } +// 2 - a simple Set type is defined +function uniqSet(arr) { + var seen = new Set(); + return arr.filter(function (el) { + if (!seen.has(el)) { + seen.add(el); + return true; + } - const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_5__["buildProjectGraph"])(projects); - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`Found [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(projects.size.toString())}] projects:\n`)); - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(Object(_utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__["renderProjectsTree"])(config.rootPath, projects)); - await command.run(projects, projectGraph, _objectSpread({}, config, { - kbn - })); - } catch (e) { - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold.red(`\n[${command.name}] failed:\n`)); + return false; + }); +} - if (e instanceof _utils_errors__WEBPACK_IMPORTED_MODULE_3__["CliError"]) { - const msg = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.red(`CliError: ${e.message}\n`); - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(wrap_ansi__WEBPACK_IMPORTED_MODULE_2___default()(msg, 80)); - const keys = Object.keys(e.meta); +// 3 - a standard Set type is defined and it has a forEach method +function uniqSetWithForEach(arr) { + var ret = []; - if (keys.length > 0) { - const metaOutput = keys.map(key => { - const value = e.meta[key]; - return `${key}: ${value}`; - }); - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write('Additional debugging info:\n'); - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(indent_string__WEBPACK_IMPORTED_MODULE_1___default()(metaOutput.join('\n'), 3)); - } - } else { - _utils_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(e.stack); - } + (new Set(arr)).forEach(function (el) { + ret.push(el); + }); - process.exit(1); - } + return ret; } -function toArray(value) { - if (value == null) { - return []; - } +// V8 currently has a broken implementation +// https://github.com/joyent/node/issues/8449 +function doesForEachActuallyWork() { + var ret = false; - return Array.isArray(value) ? value : [value]; + (new Set([true])).forEach(function (el) { + ret = el; + }); + + return ret === true; +} + +if ('Set' in global) { + if (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) { + module.exports = uniqSetWithForEach; + } else { + module.exports = uniqSet; + } +} else { + module.exports = uniqNoSet; } + /***/ }), -/* 690 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +// Approach: +// +// 1. Get the minimatch set +// 2. For each pattern in the set, PROCESS(pattern, false) +// 3. Store matches per-set, then uniq them +// +// PROCESS(pattern, inGlobStar) +// Get the first [n] items from pattern that are all strings +// Join these together. This is PREFIX. +// If there is no more remaining, then stat(PREFIX) and +// add to matches if it succeeds. END. +// +// If inGlobStar and PREFIX is symlink and points to dir +// set ENTRIES = [] +// else readdir(PREFIX) as ENTRIES +// If fail, END +// +// with ENTRIES +// If pattern[n] is GLOBSTAR +// // handle the case where the globstar match is empty +// // by pruning it out, and testing the resulting pattern +// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) +// // handle other cases. +// for ENTRY in ENTRIES (not dotfiles) +// // attach globstar + tail onto the entry +// // Mark that this entry is a globstar match +// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) +// +// else // not globstar +// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) +// Test ENTRY against pattern[n] +// If fails, continue +// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) +// +// Caveat: +// Cache all stats and readdirs results to minimize syscall. Since all +// we ever care about is existence and directory-ness, we can just keep +// `true` for files, and [children,...] for directories, or `false` for +// things that don't exist. -const stringWidth = __webpack_require__(691); -const stripAnsi = __webpack_require__(695); +module.exports = glob -const ESCAPES = new Set([ - '\u001B', - '\u009B' -]); +var fs = __webpack_require__(23) +var rp = __webpack_require__(503) +var minimatch = __webpack_require__(505) +var Minimatch = minimatch.Minimatch +var inherits = __webpack_require__(713) +var EE = __webpack_require__(379).EventEmitter +var path = __webpack_require__(16) +var assert = __webpack_require__(30) +var isAbsolute = __webpack_require__(511) +var globSync = __webpack_require__(715) +var common = __webpack_require__(716) +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var inflight = __webpack_require__(514) +var util = __webpack_require__(29) +var childrenIgnored = common.childrenIgnored +var isIgnored = common.isIgnored -const END_CODE = 39; +var once = __webpack_require__(385) -const ESCAPE_CODES = new Map([ - [0, 0], - [1, 22], - [2, 22], - [3, 23], - [4, 24], - [7, 27], - [8, 28], - [9, 29], - [30, 39], - [31, 39], - [32, 39], - [33, 39], - [34, 39], - [35, 39], - [36, 39], - [37, 39], - [90, 39], - [40, 49], - [41, 49], - [42, 49], - [43, 49], - [44, 49], - [45, 49], - [46, 49], - [47, 49] -]); +function glob (pattern, options, cb) { + if (typeof options === 'function') cb = options, options = {} + if (!options) options = {} -const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`; + if (options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return globSync(pattern, options) + } -// Calculate the length of words split on ' ', ignoring -// the extra characters added by ansi escape codes -const wordLengths = str => str.split(' ').map(s => stringWidth(s)); + return new Glob(pattern, options, cb) +} -// Wrap a long word across multiple rows -// Ansi escape codes do not count towards length -const wrapWord = (rows, word, cols) => { - const arr = Array.from(word); +glob.sync = globSync +var GlobSync = glob.GlobSync = globSync.GlobSync - let insideEscape = false; - let visible = stringWidth(stripAnsi(rows[rows.length - 1])); +// old api surface +glob.glob = glob - for (const item of arr.entries()) { - const i = item[0]; - const char = item[1]; - const charLength = stringWidth(char); +function extend (origin, add) { + if (add === null || typeof add !== 'object') { + return origin + } - if (visible + charLength <= cols) { - rows[rows.length - 1] += char; - } else { - rows.push(char); - visible = 0; - } + var keys = Object.keys(add) + var i = keys.length + while (i--) { + origin[keys[i]] = add[keys[i]] + } + return origin +} - if (ESCAPES.has(char)) { - insideEscape = true; - } else if (insideEscape && char === 'm') { - insideEscape = false; - continue; - } +glob.hasMagic = function (pattern, options_) { + var options = extend({}, options_) + options.noprocess = true - if (insideEscape) { - continue; - } + var g = new Glob(pattern, options) + var set = g.minimatch.set - visible += charLength; + if (!pattern) + return false - if (visible === cols && i < arr.length - 1) { - rows.push(''); - visible = 0; - } - } + if (set.length > 1) + return true - // It's possible that the last row we copy over is only - // ansi escape characters, handle this edge-case - if (!visible && rows[rows.length - 1].length > 0 && rows.length > 1) { - rows[rows.length - 2] += rows.pop(); - } -}; + for (var j = 0; j < set[0].length; j++) { + if (typeof set[0][j] !== 'string') + return true + } -// The wrap-ansi module can be invoked -// in either 'hard' or 'soft' wrap mode -// -// 'hard' will never allow a string to take up more -// than cols characters -// -// 'soft' allows long words to expand past the column length -const exec = (str, cols, opts) => { - const options = opts || {}; + return false +} - if (str.trim() === '') { - return options.trim === false ? str : str.trim(); - } +glob.Glob = Glob +inherits(Glob, EE) +function Glob (pattern, options, cb) { + if (typeof options === 'function') { + cb = options + options = null + } - let pre = ''; - let ret = ''; - let escapeCode; + if (options && options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return new GlobSync(pattern, options) + } - const lengths = wordLengths(str); - const words = str.split(' '); - const rows = ['']; + if (!(this instanceof Glob)) + return new Glob(pattern, options, cb) - for (const item of Array.from(words).entries()) { - const i = item[0]; - const word = item[1]; + setopts(this, pattern, options) + this._didRealPath = false - rows[rows.length - 1] = options.trim === false ? rows[rows.length - 1] : rows[rows.length - 1].trim(); - let rowLength = stringWidth(rows[rows.length - 1]); + // process each pattern in the minimatch set + var n = this.minimatch.set.length - if (rowLength || word === '') { - if (rowLength === cols && options.wordWrap === false) { - // If we start with a new word but the current row length equals the length of the columns, add a new row - rows.push(''); - rowLength = 0; - } + // The matches are stored as {: true,...} so that + // duplicates are automagically pruned. + // Later, we do an Object.keys() on these. + // Keep them as a list so we can fill in when nonull is set. + this.matches = new Array(n) - rows[rows.length - 1] += ' '; - rowLength++; - } + if (typeof cb === 'function') { + cb = once(cb) + this.on('error', cb) + this.on('end', function (matches) { + cb(null, matches) + }) + } - // In 'hard' wrap mode, the length of a line is - // never allowed to extend past 'cols' - if (lengths[i] > cols && options.hard) { - if (rowLength) { - rows.push(''); - } - wrapWord(rows, word, cols); - continue; - } + var self = this + this._processing = 0 - if (rowLength + lengths[i] > cols && rowLength > 0) { - if (options.wordWrap === false && rowLength < cols) { - wrapWord(rows, word, cols); - continue; - } + this._emitQueue = [] + this._processQueue = [] + this.paused = false - rows.push(''); - } + if (this.noprocess) + return this - if (rowLength + lengths[i] > cols && options.wordWrap === false) { - wrapWord(rows, word, cols); - continue; - } + if (n === 0) + return done() - rows[rows.length - 1] += word; - } + var sync = true + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false, done) + } + sync = false - pre = rows.map(r => options.trim === false ? r : r.trim()).join('\n'); + function done () { + --self._processing + if (self._processing <= 0) { + if (sync) { + process.nextTick(function () { + self._finish() + }) + } else { + self._finish() + } + } + } +} - for (const item of Array.from(pre).entries()) { - const i = item[0]; - const char = item[1]; +Glob.prototype._finish = function () { + assert(this instanceof Glob) + if (this.aborted) + return - ret += char; + if (this.realpath && !this._didRealpath) + return this._realpath() - if (ESCAPES.has(char)) { - const code = parseFloat(/\d[^m]*/.exec(pre.slice(i, i + 4))); - escapeCode = code === END_CODE ? null : code; - } + common.finish(this) + this.emit('end', this.found) +} - const code = ESCAPE_CODES.get(Number(escapeCode)); +Glob.prototype._realpath = function () { + if (this._didRealpath) + return - if (escapeCode && code) { - if (pre[i + 1] === '\n') { - ret += wrapAnsi(code); - } else if (char === '\n') { - ret += wrapAnsi(escapeCode); - } - } - } + this._didRealpath = true - return ret; -}; + var n = this.matches.length + if (n === 0) + return this._finish() -// For each newline, invoke the method separately -module.exports = (str, cols, opts) => { - return String(str) - .normalize() - .split('\n') - .map(line => exec(line, cols, opts)) - .join('\n'); -}; + var self = this + for (var i = 0; i < this.matches.length; i++) + this._realpathSet(i, next) + + function next () { + if (--n === 0) + self._finish() + } +} +Glob.prototype._realpathSet = function (index, cb) { + var matchset = this.matches[index] + if (!matchset) + return cb() -/***/ }), -/* 691 */ -/***/ (function(module, exports, __webpack_require__) { + var found = Object.keys(matchset) + var self = this + var n = found.length + + if (n === 0) + return cb() + + var set = this.matches[index] = Object.create(null) + found.forEach(function (p, i) { + // If there's a problem with the stat, then it means that + // one or more of the links in the realpath couldn't be + // resolved. just return the abs value in that case. + p = self._makeAbs(p) + rp.realpath(p, self.realpathCache, function (er, real) { + if (!er) + set[real] = true + else if (er.syscall === 'stat') + set[p] = true + else + self.emit('error', er) // srsly wtf right here + + if (--n === 0) { + self.matches[index] = set + cb() + } + }) + }) +} + +Glob.prototype._mark = function (p) { + return common.mark(this, p) +} -"use strict"; +Glob.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} -const stripAnsi = __webpack_require__(692); -const isFullwidthCodePoint = __webpack_require__(694); +Glob.prototype.abort = function () { + this.aborted = true + this.emit('abort') +} -module.exports = str => { - if (typeof str !== 'string' || str.length === 0) { - return 0; - } +Glob.prototype.pause = function () { + if (!this.paused) { + this.paused = true + this.emit('pause') + } +} - str = stripAnsi(str); +Glob.prototype.resume = function () { + if (this.paused) { + this.emit('resume') + this.paused = false + if (this._emitQueue.length) { + var eq = this._emitQueue.slice(0) + this._emitQueue.length = 0 + for (var i = 0; i < eq.length; i ++) { + var e = eq[i] + this._emitMatch(e[0], e[1]) + } + } + if (this._processQueue.length) { + var pq = this._processQueue.slice(0) + this._processQueue.length = 0 + for (var i = 0; i < pq.length; i ++) { + var p = pq[i] + this._processing-- + this._process(p[0], p[1], p[2], p[3]) + } + } + } +} - let width = 0; +Glob.prototype._process = function (pattern, index, inGlobStar, cb) { + assert(this instanceof Glob) + assert(typeof cb === 'function') - for (let i = 0; i < str.length; i++) { - const code = str.codePointAt(i); + if (this.aborted) + return - // Ignore control characters - if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) { - continue; - } + this._processing++ + if (this.paused) { + this._processQueue.push([pattern, index, inGlobStar, cb]) + return + } - // Ignore combining characters - if (code >= 0x300 && code <= 0x36F) { - continue; - } + //console.error('PROCESS %d', this._processing, pattern) - // Surrogates - if (code > 0xFFFF) { - i++; - } + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. - width += isFullwidthCodePoint(code) ? 2 : 1; - } + // see if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index, cb) + return - return width; -}; + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } -/***/ }), -/* 692 */ -/***/ (function(module, exports, __webpack_require__) { + var remain = pattern.slice(n) -"use strict"; + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix -const ansiRegex = __webpack_require__(693); + var abs = this._makeAbs(read) -module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; + //if ignored, skip _processing + if (childrenIgnored(this, read)) + return cb() + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) +} -/***/ }), -/* 693 */ -/***/ (function(module, exports, __webpack_require__) { +Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} -"use strict"; +Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + // if the abs isn't a dir, then nothing can match! + if (!entries) + return cb() -module.exports = () => { - const pattern = [ - '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)', - '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))' - ].join('|'); + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' - return new RegExp(pattern, 'g'); -}; + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) + } + } + //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) -/***/ }), -/* 694 */ -/***/ (function(module, exports, __webpack_require__) { + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return cb() -"use strict"; + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. -/* eslint-disable yoda */ -module.exports = x => { - if (Number.isNaN(x)) { - return false; - } + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) - // code points are derived from: - // http://www.unix.org/Public/UNIDATA/EastAsianWidth.txt - if ( - x >= 0x1100 && ( - x <= 0x115f || // Hangul Jamo - x === 0x2329 || // LEFT-POINTING ANGLE BRACKET - x === 0x232a || // RIGHT-POINTING ANGLE BRACKET - // CJK Radicals Supplement .. Enclosed CJK Letters and Months - (0x2e80 <= x && x <= 0x3247 && x !== 0x303f) || - // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A - (0x3250 <= x && x <= 0x4dbf) || - // CJK Unified Ideographs .. Yi Radicals - (0x4e00 <= x && x <= 0xa4c6) || - // Hangul Jamo Extended-A - (0xa960 <= x && x <= 0xa97c) || - // Hangul Syllables - (0xac00 <= x && x <= 0xd7a3) || - // CJK Compatibility Ideographs - (0xf900 <= x && x <= 0xfaff) || - // Vertical Forms - (0xfe10 <= x && x <= 0xfe19) || - // CJK Compatibility Forms .. Small Form Variants - (0xfe30 <= x && x <= 0xfe6b) || - // Halfwidth and Fullwidth Forms - (0xff01 <= x && x <= 0xff60) || - (0xffe0 <= x && x <= 0xffe6) || - // Kana Supplement - (0x1b000 <= x && x <= 0x1b001) || - // Enclosed Ideographic Supplement - (0x1f200 <= x && x <= 0x1f251) || - // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane - (0x20000 <= x && x <= 0x3fffd) - ) - ) { - return true; - } + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } - return false; -}; + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this._emitMatch(index, e) + } + // This was the last one, and no stats were needed + return cb() + } + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + this._process([e].concat(remain), index, inGlobStar, cb) + } + cb() +} -/***/ }), -/* 695 */ -/***/ (function(module, exports, __webpack_require__) { +Glob.prototype._emitMatch = function (index, e) { + if (this.aborted) + return -"use strict"; + if (isIgnored(this, e)) + return -const ansiRegex = __webpack_require__(696); + if (this.paused) { + this._emitQueue.push([index, e]) + return + } -module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; + var abs = isAbsolute(e) ? e : this._makeAbs(e) + if (this.mark) + e = this._mark(e) -/***/ }), -/* 696 */ -/***/ (function(module, exports, __webpack_require__) { + if (this.absolute) + e = abs -"use strict"; + if (this.matches[index][e]) + return + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return + } -module.exports = () => { - const pattern = [ - '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)', - '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))' - ].join('|'); + this.matches[index][e] = true - return new RegExp(pattern, 'g'); -}; + var st = this.statCache[abs] + if (st) + this.emit('stat', e, st) + this.emit('match', e) +} -/***/ }), -/* 697 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +Glob.prototype._readdirInGlobStar = function (abs, cb) { + if (this.aborted) + return -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderProjectsTree", function() { return renderProjectsTree; }); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(16); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); -/* - * 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. - */ + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false, cb) + var lstatkey = 'lstat\0' + abs + var self = this + var lstatcb = inflight(lstatkey, lstatcb_) -const projectKey = Symbol('__project'); -function renderProjectsTree(rootPath, projects) { - const projectsTree = buildProjectsTree(rootPath, projects); - return treeToString(createTreeStructure(projectsTree)); -} + if (lstatcb) + fs.lstat(abs, lstatcb) -function treeToString(tree) { - return [tree.name].concat(childrenToStrings(tree.children, '')).join('\n'); -} + function lstatcb_ (er, lstat) { + if (er && er.code === 'ENOENT') + return cb() -function childrenToStrings(tree, treePrefix) { - if (tree === undefined) { - return []; - } + var isSym = lstat && lstat.isSymbolicLink() + self.symlinks[abs] = isSym - let strings = []; - tree.forEach((node, index) => { - const isLastNode = tree.length - 1 === index; - const nodePrefix = isLastNode ? '└── ' : '├── '; - const childPrefix = isLastNode ? ' ' : '│ '; - const childrenPrefix = treePrefix + childPrefix; - strings.push(`${treePrefix}${nodePrefix}${node.name}`); - strings = strings.concat(childrenToStrings(node.children, childrenPrefix)); - }); - return strings; + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && lstat && !lstat.isDirectory()) { + self.cache[abs] = 'FILE' + cb() + } else + self._readdir(abs, false, cb) + } } -function createTreeStructure(tree) { - let name; - const children = []; +Glob.prototype._readdir = function (abs, inGlobStar, cb) { + if (this.aborted) + return - for (const [dir, project] of tree.entries()) { - // This is a leaf node (aka a project) - if (typeof project === 'string') { - name = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(project); - continue; - } // If there's only one project and the key indicates it's a leaf node, we - // know that we're at a package folder that contains a package.json, so we - // "inline it" so we don't get unnecessary levels, i.e. we'll just see - // `foo` instead of `foo -> foo`. + cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) + if (!cb) + return + //console.error('RD %j %j', +inGlobStar, abs) + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs, cb) - if (project.size === 1 && project.has(projectKey)) { - const projectName = project.get(projectKey); - children.push({ - children: [], - name: dirOrProjectName(dir, projectName) - }); - continue; - } + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return cb() - const subtree = createTreeStructure(project); // If the name is specified, we know there's a package at the "root" of the - // subtree itself. + if (Array.isArray(c)) + return cb(null, c) + } - if (subtree.name !== undefined) { - const projectName = subtree.name; - children.push({ - children: subtree.children, - name: dirOrProjectName(dir, projectName) - }); - continue; - } // Special-case whenever we have one child, so we don't get unnecessary - // folders in the output. E.g. instead of `foo -> bar -> baz` we get - // `foo/bar/baz` instead. + var self = this + fs.readdir(abs, readdirCb(this, abs, cb)) +} +function readdirCb (self, abs, cb) { + return function (er, entries) { + if (er) + self._readdirError(abs, er, cb) + else + self._readdirEntries(abs, entries, cb) + } +} - if (subtree.children && subtree.children.length === 1) { - const child = subtree.children[0]; - const newName = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(path__WEBPACK_IMPORTED_MODULE_1___default.a.join(dir.toString(), child.name)); - children.push({ - children: child.children, - name: newName - }); - continue; - } +Glob.prototype._readdirEntries = function (abs, entries, cb) { + if (this.aborted) + return - children.push({ - children: subtree.children, - name: chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(dir.toString()) - }); + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } } - return { - name, - children - }; + this.cache[abs] = entries + return cb(null, entries) } -function dirOrProjectName(dir, projectName) { - return dir === projectName ? chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(dir) : chalk__WEBPACK_IMPORTED_MODULE_0___default.a`{dim ${dir.toString()} ({reset.green ${projectName}})}`; -} +Glob.prototype._readdirError = function (f, er, cb) { + if (this.aborted) + return -function buildProjectsTree(rootPath, projects) { - const tree = new Map(); + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + var abs = this._makeAbs(f) + this.cache[abs] = 'FILE' + if (abs === this.cwdAbs) { + var error = new Error(er.code + ' invalid cwd ' + this.cwd) + error.path = this.cwd + error.code = er.code + this.emit('error', error) + this.abort() + } + break - for (const project of projects.values()) { - if (rootPath === project.path) { - tree.set(projectKey, project.name); - } else { - const relativeProjectPath = path__WEBPACK_IMPORTED_MODULE_1___default.a.relative(rootPath, project.path); - addProjectToTree(tree, relativeProjectPath.split(path__WEBPACK_IMPORTED_MODULE_1___default.a.sep), project); - } + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break + + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) { + this.emit('error', er) + // If the error is handled, then we abort + // if not, we threw out of here + this.abort() + } + if (!this.silent) + console.error('glob error', er) + break } - return tree; + return cb() } -function addProjectToTree(tree, pathParts, project) { - if (pathParts.length === 0) { - tree.set(projectKey, project.name); - } else { - const [currentDir, ...rest] = pathParts; - - if (!tree.has(currentDir)) { - tree.set(currentDir, new Map()); - } - - const subtree = tree.get(currentDir); - addProjectToTree(subtree, rest, project); - } +Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) } -/***/ }), -/* 698 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Kibana", function() { return Kibana; }); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(16); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(699); -/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(501); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(580); -function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } +Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + //console.error('pgs2', prefix, remain[0], entries) -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return cb() -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) -/* - * 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. - */ + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false, cb) + var isSym = this.symlinks[abs] + var len = entries.length + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return cb() + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue -/** - * Helper class for dealing with a set of projects as children of - * the Kibana project. The kbn/pm is currently implemented to be - * more generic, where everything is an operation of generic projects, - * but that leads to exceptions where we need the kibana project and - * do things like `project.get('kibana')!`. - * - * Using this helper we can restructre the generic list of projects - * as a Kibana object which encapulates all the projects in the - * workspace and knows about the root Kibana project. - */ + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true, cb) -class Kibana { - static async loadFrom(rootPath) { - return new Kibana((await Object(_projects__WEBPACK_IMPORTED_MODULE_2__["getProjects"])(rootPath, Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])({ - rootPath - })))); + var below = gspref.concat(entries[i], remain) + this._process(below, index, true, cb) } - constructor(allWorkspaceProjects) { - this.allWorkspaceProjects = allWorkspaceProjects; - - _defineProperty(this, "kibanaProject", void 0); + cb() +} - const kibanaProject = allWorkspaceProjects.get('kibana'); +Glob.prototype._processSimple = function (prefix, index, cb) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var self = this + this._stat(prefix, function (er, exists) { + self._processSimple2(prefix, index, er, exists, cb) + }) +} +Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { - if (!kibanaProject) { - throw new TypeError('Unable to create Kibana object without all projects, including the Kibana project.'); - } + //console.error('ps2', prefix, exists) - this.kibanaProject = kibanaProject; - } - /** make an absolute path by resolving subPath relative to the kibana repo */ + if (!this.matches[index]) + this.matches[index] = Object.create(null) + // If it doesn't exist, then just mark the lack of results + if (!exists) + return cb() - getAbsolute(...subPath) { - return path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(this.kibanaProject.path, ...subPath); + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } } - /** convert an absolute path to a relative path, relative to the kibana repo */ + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') - getRelative(absolute) { - return path__WEBPACK_IMPORTED_MODULE_0___default.a.relative(this.kibanaProject.path, absolute); - } - /** get a copy of the map of all projects in the kibana workspace */ - + // Mark this as a match + this._emitMatch(index, prefix) + cb() +} - getAllProjects() { - return new Map(this.allWorkspaceProjects); - } - /** determine if a project with the given name exists */ +// Returns either 'DIR', 'FILE', or false +Glob.prototype._stat = function (f, cb) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' + if (f.length > this.maxLength) + return cb() - hasProject(name) { - return this.allWorkspaceProjects.has(name); - } - /** get a specific project, throws if the name is not known (use hasProject() first) */ + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (Array.isArray(c)) + c = 'DIR' - getProject(name) { - const project = this.allWorkspaceProjects.get(name); + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return cb(null, c) - if (!project) { - throw new Error(`No package with name "${name}" in the workspace`); - } + if (needDir && c === 'FILE') + return cb() - return project; + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. } - /** get a project and all of the projects it depends on in a ProjectMap */ - - getProjectAndDeps(name) { - const project = this.getProject(name); - return Object(_projects__WEBPACK_IMPORTED_MODULE_2__["includeTransitiveProjects"])([project], this.allWorkspaceProjects); + var exists + var stat = this.statCache[abs] + if (stat !== undefined) { + if (stat === false) + return cb(null, stat) + else { + var type = stat.isDirectory() ? 'DIR' : 'FILE' + if (needDir && type === 'FILE') + return cb() + else + return cb(null, type, stat) + } } - /** filter the projects to just those matching certain paths/include/exclude tags */ - - - getFilteredProjects(options) { - const allProjects = this.getAllProjects(); - const filteredProjects = new Map(); - const pkgJsonPaths = Array.from(allProjects.values()).map(p => p.packageJsonLocation); - const filteredPkgJsonGlobs = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])(_objectSpread({}, options, { - rootPath: this.kibanaProject.path - })).map(g => path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(g, 'package.json')); - const matchingPkgJsonPaths = multimatch__WEBPACK_IMPORTED_MODULE_1___default()(pkgJsonPaths, filteredPkgJsonGlobs); - for (const project of allProjects.values()) { - const pathMatches = matchingPkgJsonPaths.includes(project.packageJsonLocation); - const notExcluded = !options.exclude.includes(project.name); - const isIncluded = !options.include.length || options.include.includes(project.name); + var self = this + var statcb = inflight('stat\0' + abs, lstatcb_) + if (statcb) + fs.lstat(abs, statcb) - if (pathMatches && notExcluded && isIncluded) { - filteredProjects.set(project.name, project); - } + function lstatcb_ (er, lstat) { + if (lstat && lstat.isSymbolicLink()) { + // If it's a symlink, then treat it as the target, unless + // the target does not exist, then treat it as a file. + return fs.stat(abs, function (er, stat) { + if (er) + self._stat2(f, abs, null, lstat, cb) + else + self._stat2(f, abs, er, stat, cb) + }) + } else { + self._stat2(f, abs, er, lstat, cb) } - - return filteredProjects; } - } -/***/ }), -/* 699 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const minimatch = __webpack_require__(505); -const arrayUnion = __webpack_require__(700); -const arrayDiffer = __webpack_require__(701); -const arrify = __webpack_require__(702); +Glob.prototype._stat2 = function (f, abs, er, stat, cb) { + if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { + this.statCache[abs] = false + return cb() + } -module.exports = (list, patterns, options = {}) => { - list = arrify(list); - patterns = arrify(patterns); + var needDir = f.slice(-1) === '/' + this.statCache[abs] = stat - if (list.length === 0 || patterns.length === 0) { - return []; - } + if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) + return cb(null, false, stat) - return patterns.reduce((result, pattern) => { - let process = arrayUnion; + var c = true + if (stat) + c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c - if (pattern[0] === '!') { - pattern = pattern.slice(1); - process = arrayDiffer; - } + if (needDir && c === 'FILE') + return cb() - return process(result, minimatch.match(list, pattern, options)); - }, []); -}; + return cb(null, c, stat) +} /***/ }), -/* 700 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +try { + var util = __webpack_require__(29); + /* istanbul ignore next */ + if (typeof util.inherits !== 'function') throw ''; + module.exports = util.inherits; +} catch (e) { + /* istanbul ignore next */ + module.exports = __webpack_require__(714); +} -module.exports = (...arguments_) => { - return [...new Set([].concat(...arguments_))]; -}; +/***/ }), +/* 714 */ +/***/ (function(module, exports) { + +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) + } + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } + } +} /***/ }), -/* 701 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +module.exports = globSync +globSync.GlobSync = GlobSync +var fs = __webpack_require__(23) +var rp = __webpack_require__(503) +var minimatch = __webpack_require__(505) +var Minimatch = minimatch.Minimatch +var Glob = __webpack_require__(712).Glob +var util = __webpack_require__(29) +var path = __webpack_require__(16) +var assert = __webpack_require__(30) +var isAbsolute = __webpack_require__(511) +var common = __webpack_require__(716) +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var childrenIgnored = common.childrenIgnored +var isIgnored = common.isIgnored -const arrayDiffer = (array, ...values) => { - const rest = new Set([].concat(...values)); - return array.filter(element => !rest.has(element)); -}; +function globSync (pattern, options) { + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') -module.exports = arrayDiffer; + return new GlobSync(pattern, options).found +} +function GlobSync (pattern, options) { + if (!pattern) + throw new Error('must provide pattern') -/***/ }), -/* 702 */ -/***/ (function(module, exports, __webpack_require__) { + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') -"use strict"; + if (!(this instanceof GlobSync)) + return new GlobSync(pattern, options) + setopts(this, pattern, options) -const arrify = value => { - if (value === null || value === undefined) { - return []; - } + if (this.noprocess) + return this - if (Array.isArray(value)) { - return value; - } + var n = this.minimatch.set.length + this.matches = new Array(n) + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false) + } + this._finish() +} - if (typeof value === 'string') { - return [value]; - } +GlobSync.prototype._finish = function () { + assert(this instanceof GlobSync) + if (this.realpath) { + var self = this + this.matches.forEach(function (matchset, index) { + var set = self.matches[index] = Object.create(null) + for (var p in matchset) { + try { + p = self._makeAbs(p) + var real = rp.realpathSync(p, self.realpathCache) + set[real] = true + } catch (er) { + if (er.syscall === 'stat') + set[self._makeAbs(p)] = true + else + throw er + } + } + }) + } + common.finish(this) +} - if (typeof value[Symbol.iterator] === 'function') { - return [...value]; - } - return [value]; -}; +GlobSync.prototype._process = function (pattern, index, inGlobStar) { + assert(this instanceof GlobSync) -module.exports = arrify; + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. + // See if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index) + return -/***/ }), -/* 703 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(704); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } -/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(914); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); + var remain = pattern.slice(n) -/* - * 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. - */ + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix + var abs = this._makeAbs(read) + //if ignored, skip processing + if (childrenIgnored(this, read)) + return -/***/ }), -/* 704 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar) +} -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(705); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(588); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(580); -/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34); -/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(517); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(501); -/* - * 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. - */ +GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { + var entries = this._readdir(abs, inGlobStar) + // if the abs isn't a dir, then nothing can match! + if (!entries) + return + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) + } + } + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) -async function buildProductionProjects({ - kibanaRoot, - buildRoot, - onlyOSS -}) { - const projects = await getProductionProjects(kibanaRoot, onlyOSS); - const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["buildProjectGraph"])(projects); - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["topologicallyBatchProjects"])(projects, projectGraph); - const projectNames = [...projects.values()].map(project => project.name); - _utils_log__WEBPACK_IMPORTED_MODULE_5__["log"].write(`Preparing production build for [${projectNames.join(', ')}]`); + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix.slice(-1) !== '/') + e = prefix + '/' + e + else + e = prefix + e + } - for (const batch of batchedProjects) { - for (const project of batch) { - await deleteTarget(project); - await buildProject(project); - await copyToBuild(project, kibanaRoot, buildRoot); + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this._emitMatch(index, e) } + // This was the last one, and no stats were needed + return + } + + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) + newPattern = [prefix, e] + else + newPattern = [e] + this._process(newPattern.concat(remain), index, inGlobStar) } } -/** - * Returns the subset of projects that should be built into the production - * bundle. As we copy these into Kibana's `node_modules` during the build step, - * and let Kibana's build process be responsible for installing dependencies, - * we only include Kibana's transitive _production_ dependencies. If onlyOSS - * is supplied, we omit projects with build.oss in their package.json set to false. - */ -async function getProductionProjects(rootPath, onlyOSS) { - const projectPaths = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])({ - rootPath - }); - const projects = await Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["getProjects"])(rootPath, projectPaths); - const projectsSubset = [projects.get('kibana')]; - if (projects.has('x-pack')) { - projectsSubset.push(projects.get('x-pack')); - } +GlobSync.prototype._emitMatch = function (index, e) { + if (isIgnored(this, e)) + return - const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, { - onlyProductionDependencies: true - }); // We remove Kibana, as we're already building Kibana + var abs = this._makeAbs(e) - productionProjects.delete('kibana'); + if (this.mark) + e = this._mark(e) - if (onlyOSS) { - productionProjects.forEach(project => { - if (project.getBuildConfig().oss === false) { - productionProjects.delete(project.json.name); - } - }); + if (this.absolute) { + e = abs } - return productionProjects; -} - -async function deleteTarget(project) { - const targetDir = project.targetLocation; + if (this.matches[index][e]) + return - if (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isDirectory"])(targetDir)) { - await del__WEBPACK_IMPORTED_MODULE_1___default()(targetDir, { - force: true - }); + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return } -} -async function buildProject(project) { - if (project.hasScript('build')) { - await project.runScript('build'); - } + this.matches[index][e] = true + + if (this.stat) + this._stat(e) } -/** - * Copy all the project's files from its "intermediate build directory" and - * into the build. The intermediate directory can either be the root of the - * project or some other location defined in the project's `package.json`. - * - * When copying all the files into the build, we exclude `node_modules` because - * we want the Kibana build to be responsible for actually installing all - * dependencies. The primary reason for allowing the Kibana build process to - * manage dependencies is that it will "dedupe" them, so we don't include - * unnecessary copies of dependencies. - */ -async function copyToBuild(project, kibanaRoot, buildRoot) { - // We want the package to have the same relative location within the build - const relativeProjectPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["relative"])(kibanaRoot, project.path); - const buildProjectPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(buildRoot, relativeProjectPath); - await cpy__WEBPACK_IMPORTED_MODULE_0___default()(['**/*', '!node_modules/**'], buildProjectPath, { - cwd: project.getIntermediateBuildDirectory(), - dot: true, - nodir: true, - parents: true - }); // If a project is using an intermediate build directory, we special-case our - // handling of `package.json`, as the project build process might have copied - // (a potentially modified) `package.json` into the intermediate build - // directory already. If so, we want to use that `package.json` as the basis - // for creating the production-ready `package.json`. If it's not present in - // the intermediate build, we fall back to using the project's already defined - // `package.json`. +GlobSync.prototype._readdirInGlobStar = function (abs) { + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false) - const packageJson = (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isFile"])(Object(path__WEBPACK_IMPORTED_MODULE_2__["join"])(buildProjectPath, 'package.json'))) ? await Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_6__["readPackageJson"])(buildProjectPath) : project.json; - await Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_6__["writePackageJson"])(buildProjectPath, packageJson); -} + var entries + var lstat + var stat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + if (er.code === 'ENOENT') { + // lstat failed, doesn't exist + return null + } + } -/***/ }), -/* 705 */ -/***/ (function(module, exports, __webpack_require__) { + var isSym = lstat && lstat.isSymbolicLink() + this.symlinks[abs] = isSym -"use strict"; + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && lstat && !lstat.isDirectory()) + this.cache[abs] = 'FILE' + else + entries = this._readdir(abs, false) -const EventEmitter = __webpack_require__(379); -const path = __webpack_require__(16); -const arrify = __webpack_require__(706); -const globby = __webpack_require__(707); -const cpFile = __webpack_require__(905); -const CpyError = __webpack_require__(912); + return entries +} -const preprocessSrcPath = (srcPath, options) => options.cwd ? path.resolve(options.cwd, srcPath) : srcPath; +GlobSync.prototype._readdir = function (abs, inGlobStar) { + var entries -const preprocessDestPath = (srcPath, dest, options) => { - let basename = path.basename(srcPath); - const dirname = path.dirname(srcPath); + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs) - if (typeof options.rename === 'string') { - basename = options.rename; - } else if (typeof options.rename === 'function') { - basename = options.rename(basename); - } + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return null - if (options.cwd) { - dest = path.resolve(options.cwd, dest); - } + if (Array.isArray(c)) + return c + } - if (options.parents) { - return path.join(dest, dirname, basename); - } + try { + return this._readdirEntries(abs, fs.readdirSync(abs)) + } catch (er) { + this._readdirError(abs, er) + return null + } +} - return path.join(dest, basename); -}; +GlobSync.prototype._readdirEntries = function (abs, entries) { + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } + } -const cpy = (src, dest, options = {}) => { - src = arrify(src); + this.cache[abs] = entries - const progressEmitter = new EventEmitter(); + // mark and cache dir-ness + return entries +} - if (src.length === 0 || !dest) { - const promise = Promise.reject(new CpyError('`files` and `destination` required')); - promise.on = (...args) => { - progressEmitter.on(...args); - return promise; - }; +GlobSync.prototype._readdirError = function (f, er) { + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + var abs = this._makeAbs(f) + this.cache[abs] = 'FILE' + if (abs === this.cwdAbs) { + var error = new Error(er.code + ' invalid cwd ' + this.cwd) + error.path = this.cwd + error.code = er.code + throw error + } + break - return promise; - } + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break - const copyStatus = new Map(); - let completedFiles = 0; - let completedSize = 0; + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) + throw er + if (!this.silent) + console.error('glob error', er) + break + } +} - const promise = globby(src, options) - .catch(error => { - throw new CpyError(`Cannot glob \`${src}\`: ${error.message}`, error); - }) - .then(files => { - if (files.length === 0) { - progressEmitter.emit('progress', { - totalFiles: 0, - percent: 1, - completedFiles: 0, - completedSize: 0 - }); - } +GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { - return Promise.all(files.map(srcPath => { - const from = preprocessSrcPath(srcPath, options); - const to = preprocessDestPath(srcPath, dest, options); + var entries = this._readdir(abs, inGlobStar) - return cpFile(from, to, options) - .on('progress', event => { - const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return - if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { - completedSize -= fileStatus.written; - completedSize += event.written; + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) - if (event.percent === 1 && fileStatus.percent !== 1) { - completedFiles++; - } + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false) - copyStatus.set(event.src, {written: event.written, percent: event.percent}); + var len = entries.length + var isSym = this.symlinks[abs] - progressEmitter.emit('progress', { - totalFiles: files.length, - percent: completedFiles / files.length, - completedFiles, - completedSize - }); - } - }) - .then(() => to) - .catch(error => { - throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); - }); - })); - }); + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return - promise.on = (...args) => { - progressEmitter.on(...args); - return promise; - }; + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue - return promise; -}; + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true) -module.exports = cpy; -// TODO: Remove this for the next major release -module.exports.default = cpy; + var below = gspref.concat(entries[i], remain) + this._process(below, index, true) + } +} +GlobSync.prototype._processSimple = function (prefix, index) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var exists = this._stat(prefix) -/***/ }), -/* 706 */ -/***/ (function(module, exports, __webpack_require__) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) -"use strict"; + // If it doesn't exist, then just mark the lack of results + if (!exists) + return -module.exports = function (val) { - if (val === null || val === undefined) { - return []; - } + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } + } - return Array.isArray(val) ? val : [val]; -}; + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') + // Mark this as a match + this._emitMatch(index, prefix) +} -/***/ }), -/* 707 */ -/***/ (function(module, exports, __webpack_require__) { +// Returns either 'DIR', 'FILE', or false +GlobSync.prototype._stat = function (f) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' -"use strict"; + if (f.length > this.maxLength) + return false -const fs = __webpack_require__(23); -const arrayUnion = __webpack_require__(708); -const glob = __webpack_require__(502); -const fastGlob = __webpack_require__(710); -const dirGlob = __webpack_require__(898); -const gitignore = __webpack_require__(901); + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] -const DEFAULT_FILTER = () => false; + if (Array.isArray(c)) + c = 'DIR' -const isNegative = pattern => pattern[0] === '!'; + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return c -const assertPatternsInput = patterns => { - if (!patterns.every(x => typeof x === 'string')) { - throw new TypeError('Patterns must be a string or an array of strings'); - } -}; + if (needDir && c === 'FILE') + return false -const checkCwdOption = options => { - if (options && options.cwd && !fs.statSync(options.cwd).isDirectory()) { - throw new Error('The `cwd` option must be a path to a directory'); - } -}; + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } -const generateGlobTasks = (patterns, taskOptions) => { - patterns = arrayUnion([].concat(patterns)); - assertPatternsInput(patterns); - checkCwdOption(taskOptions); + var exists + var stat = this.statCache[abs] + if (!stat) { + var lstat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { + this.statCache[abs] = false + return false + } + } - const globTasks = []; + if (lstat && lstat.isSymbolicLink()) { + try { + stat = fs.statSync(abs) + } catch (er) { + stat = lstat + } + } else { + stat = lstat + } + } - taskOptions = Object.assign({ - ignore: [], - expandDirectories: true - }, taskOptions); + this.statCache[abs] = stat - patterns.forEach((pattern, i) => { - if (isNegative(pattern)) { - return; - } + var c = true + if (stat) + c = stat.isDirectory() ? 'DIR' : 'FILE' - const ignore = patterns - .slice(i) - .filter(isNegative) - .map(pattern => pattern.slice(1)); + this.cache[abs] = this.cache[abs] || c - const options = Object.assign({}, taskOptions, { - ignore: taskOptions.ignore.concat(ignore) - }); + if (needDir && c === 'FILE') + return false - globTasks.push({pattern, options}); - }); + return c +} - return globTasks; -}; +GlobSync.prototype._mark = function (p) { + return common.mark(this, p) +} -const globDirs = (task, fn) => { - let options = {}; - if (task.options.cwd) { - options.cwd = task.options.cwd; - } +GlobSync.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} - if (Array.isArray(task.options.expandDirectories)) { - options = Object.assign(options, {files: task.options.expandDirectories}); - } else if (typeof task.options.expandDirectories === 'object') { - options = Object.assign(options, task.options.expandDirectories); - } - return fn(task.pattern, options); -}; +/***/ }), +/* 716 */ +/***/ (function(module, exports, __webpack_require__) { -const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern]; +exports.alphasort = alphasort +exports.alphasorti = alphasorti +exports.setopts = setopts +exports.ownProp = ownProp +exports.makeAbs = makeAbs +exports.finish = finish +exports.mark = mark +exports.isIgnored = isIgnored +exports.childrenIgnored = childrenIgnored -const globToTask = task => glob => { - const {options} = task; - if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { - options.ignore = dirGlob.sync(options.ignore); - } +function ownProp (obj, field) { + return Object.prototype.hasOwnProperty.call(obj, field) +} - return { - pattern: glob, - options - }; -}; +var path = __webpack_require__(16) +var minimatch = __webpack_require__(505) +var isAbsolute = __webpack_require__(511) +var Minimatch = minimatch.Minimatch -const globby = (patterns, options) => { - let globTasks; +function alphasorti (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()) +} - try { - globTasks = generateGlobTasks(patterns, options); - } catch (error) { - return Promise.reject(error); - } +function alphasort (a, b) { + return a.localeCompare(b) +} - const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob)) - .then(globs => Promise.all(globs.map(globToTask(task)))) - )) - .then(tasks => arrayUnion(...tasks)); +function setupIgnores (self, options) { + self.ignore = options.ignore || [] - const getFilter = () => { - return Promise.resolve( - options && options.gitignore ? - gitignore({cwd: options.cwd, ignore: options.ignore}) : - DEFAULT_FILTER - ); - }; + if (!Array.isArray(self.ignore)) + self.ignore = [self.ignore] - return getFilter() - .then(filter => { - return getTasks - .then(tasks => Promise.all(tasks.map(task => fastGlob(task.pattern, task.options)))) - .then(paths => arrayUnion(...paths)) - .then(paths => paths.filter(p => !filter(p))); - }); -}; + if (self.ignore.length) { + self.ignore = self.ignore.map(ignoreMap) + } +} -module.exports = globby; -// TODO: Remove this for the next major release -module.exports.default = globby; +// ignore patterns are always in dot:true mode. +function ignoreMap (pattern) { + var gmatcher = null + if (pattern.slice(-3) === '/**') { + var gpattern = pattern.replace(/(\/\*\*)+$/, '') + gmatcher = new Minimatch(gpattern, { dot: true }) + } -module.exports.sync = (patterns, options) => { - const globTasks = generateGlobTasks(patterns, options); + return { + matcher: new Minimatch(pattern, { dot: true }), + gmatcher: gmatcher + } +} - const getFilter = () => { - return options && options.gitignore ? - gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : - DEFAULT_FILTER; - }; +function setopts (self, pattern, options) { + if (!options) + options = {} - const tasks = globTasks.reduce((tasks, task) => { - const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); - return tasks.concat(newTask); - }, []); + // base-matching: just use globstar for that. + if (options.matchBase && -1 === pattern.indexOf("/")) { + if (options.noglobstar) { + throw new Error("base matching requires globstar") + } + pattern = "**/" + pattern + } - const filter = getFilter(); - return tasks.reduce( - (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), - [] - ).filter(p => !filter(p)); -}; + self.silent = !!options.silent + self.pattern = pattern + self.strict = options.strict !== false + self.realpath = !!options.realpath + self.realpathCache = options.realpathCache || Object.create(null) + self.follow = !!options.follow + self.dot = !!options.dot + self.mark = !!options.mark + self.nodir = !!options.nodir + if (self.nodir) + self.mark = true + self.sync = !!options.sync + self.nounique = !!options.nounique + self.nonull = !!options.nonull + self.nosort = !!options.nosort + self.nocase = !!options.nocase + self.stat = !!options.stat + self.noprocess = !!options.noprocess + self.absolute = !!options.absolute -module.exports.generateGlobTasks = generateGlobTasks; + self.maxLength = options.maxLength || Infinity + self.cache = options.cache || Object.create(null) + self.statCache = options.statCache || Object.create(null) + self.symlinks = options.symlinks || Object.create(null) -module.exports.hasMagic = (patterns, options) => [] - .concat(patterns) - .some(pattern => glob.hasMagic(pattern, options)); + setupIgnores(self, options) -module.exports.gitignore = gitignore; + self.changedCwd = false + var cwd = process.cwd() + if (!ownProp(options, "cwd")) + self.cwd = cwd + else { + self.cwd = path.resolve(options.cwd) + self.changedCwd = self.cwd !== cwd + } + self.root = options.root || path.resolve(self.cwd, "/") + self.root = path.resolve(self.root) + if (process.platform === "win32") + self.root = self.root.replace(/\\/g, "/") -/***/ }), -/* 708 */ -/***/ (function(module, exports, __webpack_require__) { + // TODO: is an absolute `cwd` supposed to be resolved against `root`? + // e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test') + self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd) + if (process.platform === "win32") + self.cwdAbs = self.cwdAbs.replace(/\\/g, "/") + self.nomount = !!options.nomount -"use strict"; + // disable comments and negation in Minimatch. + // Note that they are not supported in Glob itself anyway. + options.nonegate = true + options.nocomment = true -var arrayUniq = __webpack_require__(709); + self.minimatch = new Minimatch(pattern, options) + self.options = self.minimatch.options +} -module.exports = function () { - return arrayUniq([].concat.apply([], arguments)); -}; +function finish (self) { + var nou = self.nounique + var all = nou ? [] : Object.create(null) + for (var i = 0, l = self.matches.length; i < l; i ++) { + var matches = self.matches[i] + if (!matches || Object.keys(matches).length === 0) { + if (self.nonull) { + // do like the shell, and spit out the literal glob + var literal = self.minimatch.globSet[i] + if (nou) + all.push(literal) + else + all[literal] = true + } + } else { + // had matches + var m = Object.keys(matches) + if (nou) + all.push.apply(all, m) + else + m.forEach(function (m) { + all[m] = true + }) + } + } -/***/ }), -/* 709 */ -/***/ (function(module, exports, __webpack_require__) { + if (!nou) + all = Object.keys(all) -"use strict"; + if (!self.nosort) + all = all.sort(self.nocase ? alphasorti : alphasort) + // at *some* point we statted all of these + if (self.mark) { + for (var i = 0; i < all.length; i++) { + all[i] = self._mark(all[i]) + } + if (self.nodir) { + all = all.filter(function (e) { + var notDir = !(/\/$/.test(e)) + var c = self.cache[e] || self.cache[makeAbs(self, e)] + if (notDir && c) + notDir = c !== 'DIR' && !Array.isArray(c) + return notDir + }) + } + } -// there's 3 implementations written in increasing order of efficiency + if (self.ignore.length) + all = all.filter(function(m) { + return !isIgnored(self, m) + }) -// 1 - no Set type is defined -function uniqNoSet(arr) { - var ret = []; + self.found = all +} - for (var i = 0; i < arr.length; i++) { - if (ret.indexOf(arr[i]) === -1) { - ret.push(arr[i]); - } - } +function mark (self, p) { + var abs = makeAbs(self, p) + var c = self.cache[abs] + var m = p + if (c) { + var isDir = c === 'DIR' || Array.isArray(c) + var slash = p.slice(-1) === '/' - return ret; -} + if (isDir && !slash) + m += '/' + else if (!isDir && slash) + m = m.slice(0, -1) -// 2 - a simple Set type is defined -function uniqSet(arr) { - var seen = new Set(); - return arr.filter(function (el) { - if (!seen.has(el)) { - seen.add(el); - return true; - } + if (m !== p) { + var mabs = makeAbs(self, m) + self.statCache[mabs] = self.statCache[abs] + self.cache[mabs] = self.cache[abs] + } + } - return false; - }); + return m } -// 3 - a standard Set type is defined and it has a forEach method -function uniqSetWithForEach(arr) { - var ret = []; +// lotta situps... +function makeAbs (self, f) { + var abs = f + if (f.charAt(0) === '/') { + abs = path.join(self.root, f) + } else if (isAbsolute(f) || f === '') { + abs = f + } else if (self.changedCwd) { + abs = path.resolve(self.cwd, f) + } else { + abs = path.resolve(f) + } - (new Set(arr)).forEach(function (el) { - ret.push(el); - }); + if (process.platform === 'win32') + abs = abs.replace(/\\/g, '/') - return ret; + return abs } -// V8 currently has a broken implementation -// https://github.com/joyent/node/issues/8449 -function doesForEachActuallyWork() { - var ret = false; - (new Set([true])).forEach(function (el) { - ret = el; - }); +// Return true, if pattern ends with globstar '**', for the accompanying parent directory. +// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents +function isIgnored (self, path) { + if (!self.ignore.length) + return false - return ret === true; + return self.ignore.some(function(item) { + return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) + }) } -if ('Set' in global) { - if (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) { - module.exports = uniqSetWithForEach; - } else { - module.exports = uniqSet; - } -} else { - module.exports = uniqNoSet; +function childrenIgnored (self, path) { + if (!self.ignore.length) + return false + + return self.ignore.some(function(item) { + return !!(item.gmatcher && item.gmatcher.match(path)) + }) } /***/ }), -/* 710 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(711); +const pkg = __webpack_require__(718); module.exports = pkg.async; module.exports.default = pkg.async; @@ -80438,19 +82817,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 711 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(712); -var taskManager = __webpack_require__(713); -var reader_async_1 = __webpack_require__(869); -var reader_stream_1 = __webpack_require__(893); -var reader_sync_1 = __webpack_require__(894); -var arrayUtils = __webpack_require__(896); -var streamUtils = __webpack_require__(897); +var optionsManager = __webpack_require__(719); +var taskManager = __webpack_require__(720); +var reader_async_1 = __webpack_require__(876); +var reader_stream_1 = __webpack_require__(900); +var reader_sync_1 = __webpack_require__(901); +var arrayUtils = __webpack_require__(903); +var streamUtils = __webpack_require__(904); /** * Synchronous API. */ @@ -80516,7 +82895,7 @@ function isString(source) { /***/ }), -/* 712 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80554,13 +82933,13 @@ exports.prepare = prepare; /***/ }), -/* 713 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(714); +var patternUtils = __webpack_require__(721); /** * Generate tasks based on parent directory of each pattern. */ @@ -80651,16 +83030,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 714 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var globParent = __webpack_require__(715); -var isGlob = __webpack_require__(718); -var micromatch = __webpack_require__(719); +var globParent = __webpack_require__(722); +var isGlob = __webpack_require__(725); +var micromatch = __webpack_require__(726); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -80806,15 +83185,15 @@ exports.matchAny = matchAny; /***/ }), -/* 715 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(16); -var isglob = __webpack_require__(716); -var pathDirname = __webpack_require__(717); +var isglob = __webpack_require__(723); +var pathDirname = __webpack_require__(724); var isWin32 = __webpack_require__(11).platform() === 'win32'; module.exports = function globParent(str) { @@ -80837,7 +83216,7 @@ module.exports = function globParent(str) { /***/ }), -/* 716 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -80847,7 +83226,7 @@ module.exports = function globParent(str) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(602); +var isExtglob = __webpack_require__(607); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { @@ -80868,7 +83247,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 717 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81018,7 +83397,7 @@ module.exports.win32 = win32; /***/ }), -/* 718 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -81028,7 +83407,7 @@ module.exports.win32 = win32; * Released under the MIT License. */ -var isExtglob = __webpack_require__(602); +var isExtglob = __webpack_require__(607); var chars = { '{': '}', '(': ')', '[': ']'}; module.exports = function isGlob(str, options) { @@ -81070,7 +83449,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 719 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81081,18 +83460,18 @@ module.exports = function isGlob(str, options) { */ var util = __webpack_require__(29); -var braces = __webpack_require__(720); -var toRegex = __webpack_require__(822); -var extend = __webpack_require__(830); +var braces = __webpack_require__(727); +var toRegex = __webpack_require__(829); +var extend = __webpack_require__(837); /** * Local dependencies */ -var compilers = __webpack_require__(833); -var parsers = __webpack_require__(865); -var cache = __webpack_require__(866); -var utils = __webpack_require__(867); +var compilers = __webpack_require__(840); +var parsers = __webpack_require__(872); +var cache = __webpack_require__(873); +var utils = __webpack_require__(874); var MAX_LENGTH = 1024 * 64; /** @@ -81954,7 +84333,7 @@ module.exports = micromatch; /***/ }), -/* 720 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81964,18 +84343,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(721); -var unique = __webpack_require__(733); -var extend = __webpack_require__(730); +var toRegex = __webpack_require__(728); +var unique = __webpack_require__(740); +var extend = __webpack_require__(737); /** * Local dependencies */ -var compilers = __webpack_require__(734); -var parsers = __webpack_require__(749); -var Braces = __webpack_require__(759); -var utils = __webpack_require__(735); +var compilers = __webpack_require__(741); +var parsers = __webpack_require__(756); +var Braces = __webpack_require__(766); +var utils = __webpack_require__(742); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -82279,15 +84658,15 @@ module.exports = braces; /***/ }), -/* 721 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(722); -var extend = __webpack_require__(730); -var not = __webpack_require__(732); +var define = __webpack_require__(729); +var extend = __webpack_require__(737); +var not = __webpack_require__(739); var MAX_LENGTH = 1024 * 64; /** @@ -82434,7 +84813,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 722 */ +/* 729 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82447,7 +84826,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(723); +var isDescriptor = __webpack_require__(730); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -82472,7 +84851,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 723 */ +/* 730 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82485,9 +84864,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(724); -var isAccessor = __webpack_require__(725); -var isData = __webpack_require__(728); +var typeOf = __webpack_require__(731); +var isAccessor = __webpack_require__(732); +var isData = __webpack_require__(735); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -82501,7 +84880,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 724 */ +/* 731 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -82654,7 +85033,7 @@ function isBuffer(val) { /***/ }), -/* 725 */ +/* 732 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82667,7 +85046,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(726); +var typeOf = __webpack_require__(733); // accessor descriptor properties var accessor = { @@ -82730,10 +85109,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 726 */ +/* 733 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(727); +var isBuffer = __webpack_require__(734); var toString = Object.prototype.toString; /** @@ -82852,7 +85231,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 727 */ +/* 734 */ /***/ (function(module, exports) { /*! @@ -82879,7 +85258,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 728 */ +/* 735 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82892,7 +85271,7 @@ function isSlowBuffer (obj) { -var typeOf = __webpack_require__(729); +var typeOf = __webpack_require__(736); // data descriptor properties var data = { @@ -82941,10 +85320,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 729 */ +/* 736 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(727); +var isBuffer = __webpack_require__(734); var toString = Object.prototype.toString; /** @@ -83063,13 +85442,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 730 */ +/* 737 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(731); +var isObject = __webpack_require__(738); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -83103,7 +85482,7 @@ function hasOwn(obj, key) { /***/ }), -/* 731 */ +/* 738 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83123,13 +85502,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 732 */ +/* 739 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(730); +var extend = __webpack_require__(737); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -83196,7 +85575,7 @@ module.exports = toRegex; /***/ }), -/* 733 */ +/* 740 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83246,13 +85625,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 734 */ +/* 741 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(735); +var utils = __webpack_require__(742); module.exports = function(braces, options) { braces.compiler @@ -83535,25 +85914,25 @@ function hasQueue(node) { /***/ }), -/* 735 */ +/* 742 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(736); +var splitString = __webpack_require__(743); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(730); -utils.flatten = __webpack_require__(742); -utils.isObject = __webpack_require__(740); -utils.fillRange = __webpack_require__(743); -utils.repeat = __webpack_require__(748); -utils.unique = __webpack_require__(733); +utils.extend = __webpack_require__(737); +utils.flatten = __webpack_require__(749); +utils.isObject = __webpack_require__(747); +utils.fillRange = __webpack_require__(750); +utils.repeat = __webpack_require__(755); +utils.unique = __webpack_require__(740); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -83885,7 +86264,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 736 */ +/* 743 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83898,7 +86277,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(737); +var extend = __webpack_require__(744); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -84063,14 +86442,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 737 */ +/* 744 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(738); -var assignSymbols = __webpack_require__(741); +var isExtendable = __webpack_require__(745); +var assignSymbols = __webpack_require__(748); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -84130,7 +86509,7 @@ function isEnum(obj, key) { /***/ }), -/* 738 */ +/* 745 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84143,7 +86522,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(739); +var isPlainObject = __webpack_require__(746); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -84151,7 +86530,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 739 */ +/* 746 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84164,7 +86543,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(740); +var isObject = __webpack_require__(747); function isObjectObject(o) { return isObject(o) === true @@ -84195,7 +86574,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 740 */ +/* 747 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84214,7 +86593,7 @@ module.exports = function isObject(val) { /***/ }), -/* 741 */ +/* 748 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84261,7 +86640,7 @@ module.exports = function(receiver, objects) { /***/ }), -/* 742 */ +/* 749 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84290,7 +86669,7 @@ function flat(arr, res) { /***/ }), -/* 743 */ +/* 750 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84304,10 +86683,10 @@ function flat(arr, res) { var util = __webpack_require__(29); -var isNumber = __webpack_require__(744); -var extend = __webpack_require__(730); -var repeat = __webpack_require__(746); -var toRegex = __webpack_require__(747); +var isNumber = __webpack_require__(751); +var extend = __webpack_require__(737); +var repeat = __webpack_require__(753); +var toRegex = __webpack_require__(754); /** * Return a range of numbers or letters. @@ -84505,7 +86884,7 @@ module.exports = fillRange; /***/ }), -/* 744 */ +/* 751 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84518,7 +86897,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(745); +var typeOf = __webpack_require__(752); module.exports = function isNumber(num) { var type = typeOf(num); @@ -84534,10 +86913,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 745 */ +/* 752 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(727); +var isBuffer = __webpack_require__(734); var toString = Object.prototype.toString; /** @@ -84656,7 +87035,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 746 */ +/* 753 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84733,7 +87112,7 @@ function repeat(str, num) { /***/ }), -/* 747 */ +/* 754 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84746,8 +87125,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(746); -var isNumber = __webpack_require__(744); +var repeat = __webpack_require__(753); +var isNumber = __webpack_require__(751); var cache = {}; function toRegexRange(min, max, options) { @@ -85034,7 +87413,7 @@ module.exports = toRegexRange; /***/ }), -/* 748 */ +/* 755 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85059,14 +87438,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 749 */ +/* 756 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(750); -var utils = __webpack_require__(735); +var Node = __webpack_require__(757); +var utils = __webpack_require__(742); /** * Braces parsers @@ -85426,15 +87805,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 750 */ +/* 757 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(740); -var define = __webpack_require__(751); -var utils = __webpack_require__(758); +var isObject = __webpack_require__(747); +var define = __webpack_require__(758); +var utils = __webpack_require__(765); var ownNames; /** @@ -85925,7 +88304,7 @@ exports = module.exports = Node; /***/ }), -/* 751 */ +/* 758 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85938,7 +88317,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(752); +var isDescriptor = __webpack_require__(759); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -85963,7 +88342,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 752 */ +/* 759 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85976,9 +88355,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(753); -var isAccessor = __webpack_require__(754); -var isData = __webpack_require__(756); +var typeOf = __webpack_require__(760); +var isAccessor = __webpack_require__(761); +var isData = __webpack_require__(763); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -85992,7 +88371,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 753 */ +/* 760 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86127,7 +88506,7 @@ function isBuffer(val) { /***/ }), -/* 754 */ +/* 761 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86140,7 +88519,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(755); +var typeOf = __webpack_require__(762); // accessor descriptor properties var accessor = { @@ -86203,7 +88582,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 755 */ +/* 762 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86338,7 +88717,7 @@ function isBuffer(val) { /***/ }), -/* 756 */ +/* 763 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86351,7 +88730,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(757); +var typeOf = __webpack_require__(764); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -86394,7 +88773,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 757 */ +/* 764 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86529,13 +88908,13 @@ function isBuffer(val) { /***/ }), -/* 758 */ +/* 765 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(745); +var typeOf = __webpack_require__(752); var utils = module.exports; /** @@ -87555,17 +89934,17 @@ function assert(val, message) { /***/ }), -/* 759 */ +/* 766 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(730); -var Snapdragon = __webpack_require__(760); -var compilers = __webpack_require__(734); -var parsers = __webpack_require__(749); -var utils = __webpack_require__(735); +var extend = __webpack_require__(737); +var Snapdragon = __webpack_require__(767); +var compilers = __webpack_require__(741); +var parsers = __webpack_require__(756); +var utils = __webpack_require__(742); /** * Customize Snapdragon parser and renderer @@ -87666,17 +90045,17 @@ module.exports = Braces; /***/ }), -/* 760 */ +/* 767 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(761); -var define = __webpack_require__(722); -var Compiler = __webpack_require__(790); -var Parser = __webpack_require__(819); -var utils = __webpack_require__(799); +var Base = __webpack_require__(768); +var define = __webpack_require__(729); +var Compiler = __webpack_require__(797); +var Parser = __webpack_require__(826); +var utils = __webpack_require__(806); var regexCache = {}; var cache = {}; @@ -87847,20 +90226,20 @@ module.exports.Parser = Parser; /***/ }), -/* 761 */ +/* 768 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var define = __webpack_require__(762); -var CacheBase = __webpack_require__(763); -var Emitter = __webpack_require__(764); -var isObject = __webpack_require__(740); -var merge = __webpack_require__(781); -var pascal = __webpack_require__(784); -var cu = __webpack_require__(785); +var define = __webpack_require__(769); +var CacheBase = __webpack_require__(770); +var Emitter = __webpack_require__(771); +var isObject = __webpack_require__(747); +var merge = __webpack_require__(788); +var pascal = __webpack_require__(791); +var cu = __webpack_require__(792); /** * Optionally define a custom `cache` namespace to use. @@ -88289,7 +90668,7 @@ module.exports.namespace = namespace; /***/ }), -/* 762 */ +/* 769 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88302,7 +90681,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(752); +var isDescriptor = __webpack_require__(759); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -88327,21 +90706,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 763 */ +/* 770 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(740); -var Emitter = __webpack_require__(764); -var visit = __webpack_require__(765); -var toPath = __webpack_require__(768); -var union = __webpack_require__(769); -var del = __webpack_require__(773); -var get = __webpack_require__(771); -var has = __webpack_require__(778); -var set = __webpack_require__(772); +var isObject = __webpack_require__(747); +var Emitter = __webpack_require__(771); +var visit = __webpack_require__(772); +var toPath = __webpack_require__(775); +var union = __webpack_require__(776); +var del = __webpack_require__(780); +var get = __webpack_require__(778); +var has = __webpack_require__(785); +var set = __webpack_require__(779); /** * Create a `Cache` constructor that when instantiated will @@ -88595,7 +90974,7 @@ module.exports.namespace = namespace; /***/ }), -/* 764 */ +/* 771 */ /***/ (function(module, exports, __webpack_require__) { @@ -88764,7 +91143,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 765 */ +/* 772 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88777,8 +91156,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(766); -var mapVisit = __webpack_require__(767); +var visit = __webpack_require__(773); +var mapVisit = __webpack_require__(774); module.exports = function(collection, method, val) { var result; @@ -88801,7 +91180,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 766 */ +/* 773 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88814,7 +91193,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(740); +var isObject = __webpack_require__(747); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -88841,14 +91220,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 767 */ +/* 774 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var visit = __webpack_require__(766); +var visit = __webpack_require__(773); /** * Map `visit` over an array of objects. @@ -88885,7 +91264,7 @@ function isObject(val) { /***/ }), -/* 768 */ +/* 775 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88898,7 +91277,7 @@ function isObject(val) { -var typeOf = __webpack_require__(745); +var typeOf = __webpack_require__(752); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -88925,16 +91304,16 @@ function filter(arr) { /***/ }), -/* 769 */ +/* 776 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(731); -var union = __webpack_require__(770); -var get = __webpack_require__(771); -var set = __webpack_require__(772); +var isObject = __webpack_require__(738); +var union = __webpack_require__(777); +var get = __webpack_require__(778); +var set = __webpack_require__(779); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -88962,7 +91341,7 @@ function arrayify(val) { /***/ }), -/* 770 */ +/* 777 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88998,7 +91377,7 @@ module.exports = function union(init) { /***/ }), -/* 771 */ +/* 778 */ /***/ (function(module, exports) { /*! @@ -89054,7 +91433,7 @@ function toString(val) { /***/ }), -/* 772 */ +/* 779 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89067,10 +91446,10 @@ function toString(val) { -var split = __webpack_require__(736); -var extend = __webpack_require__(730); -var isPlainObject = __webpack_require__(739); -var isObject = __webpack_require__(731); +var split = __webpack_require__(743); +var extend = __webpack_require__(737); +var isPlainObject = __webpack_require__(746); +var isObject = __webpack_require__(738); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -89116,7 +91495,7 @@ function isValidKey(key) { /***/ }), -/* 773 */ +/* 780 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89129,8 +91508,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(740); -var has = __webpack_require__(774); +var isObject = __webpack_require__(747); +var has = __webpack_require__(781); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -89155,7 +91534,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 774 */ +/* 781 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89168,9 +91547,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(775); -var hasValues = __webpack_require__(777); -var get = __webpack_require__(771); +var isObject = __webpack_require__(782); +var hasValues = __webpack_require__(784); +var get = __webpack_require__(778); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -89181,7 +91560,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 775 */ +/* 782 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89194,7 +91573,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(776); +var isArray = __webpack_require__(783); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -89202,7 +91581,7 @@ module.exports = function isObject(val) { /***/ }), -/* 776 */ +/* 783 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -89213,7 +91592,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 777 */ +/* 784 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89256,7 +91635,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 778 */ +/* 785 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89269,9 +91648,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(740); -var hasValues = __webpack_require__(779); -var get = __webpack_require__(771); +var isObject = __webpack_require__(747); +var hasValues = __webpack_require__(786); +var get = __webpack_require__(778); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -89279,7 +91658,7 @@ module.exports = function(val, prop) { /***/ }), -/* 779 */ +/* 786 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89292,8 +91671,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(780); -var isNumber = __webpack_require__(744); +var typeOf = __webpack_require__(787); +var isNumber = __webpack_require__(751); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -89346,10 +91725,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 780 */ +/* 787 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(727); +var isBuffer = __webpack_require__(734); var toString = Object.prototype.toString; /** @@ -89471,14 +91850,14 @@ module.exports = function kindOf(val) { /***/ }), -/* 781 */ +/* 788 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(782); -var forIn = __webpack_require__(783); +var isExtendable = __webpack_require__(789); +var forIn = __webpack_require__(790); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -89542,7 +91921,7 @@ module.exports = mixinDeep; /***/ }), -/* 782 */ +/* 789 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89555,7 +91934,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(739); +var isPlainObject = __webpack_require__(746); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -89563,7 +91942,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 783 */ +/* 790 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89586,7 +91965,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 784 */ +/* 791 */ /***/ (function(module, exports) { /*! @@ -89613,14 +91992,14 @@ module.exports = pascalcase; /***/ }), -/* 785 */ +/* 792 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var utils = __webpack_require__(786); +var utils = __webpack_require__(793); /** * Expose class utils @@ -89985,7 +92364,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 786 */ +/* 793 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89999,10 +92378,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(770); -utils.define = __webpack_require__(722); -utils.isObj = __webpack_require__(740); -utils.staticExtend = __webpack_require__(787); +utils.union = __webpack_require__(777); +utils.define = __webpack_require__(729); +utils.isObj = __webpack_require__(747); +utils.staticExtend = __webpack_require__(794); /** @@ -90013,7 +92392,7 @@ module.exports = utils; /***/ }), -/* 787 */ +/* 794 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90026,8 +92405,8 @@ module.exports = utils; -var copy = __webpack_require__(788); -var define = __webpack_require__(722); +var copy = __webpack_require__(795); +var define = __webpack_require__(729); var util = __webpack_require__(29); /** @@ -90110,15 +92489,15 @@ module.exports = extend; /***/ }), -/* 788 */ +/* 795 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(745); -var copyDescriptor = __webpack_require__(789); -var define = __webpack_require__(722); +var typeOf = __webpack_require__(752); +var copyDescriptor = __webpack_require__(796); +var define = __webpack_require__(729); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -90291,7 +92670,7 @@ module.exports.has = has; /***/ }), -/* 789 */ +/* 796 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90379,16 +92758,16 @@ function isObject(val) { /***/ }), -/* 790 */ +/* 797 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(791); -var define = __webpack_require__(722); -var debug = __webpack_require__(793)('snapdragon:compiler'); -var utils = __webpack_require__(799); +var use = __webpack_require__(798); +var define = __webpack_require__(729); +var debug = __webpack_require__(800)('snapdragon:compiler'); +var utils = __webpack_require__(806); /** * Create a new `Compiler` with the given `options`. @@ -90542,7 +92921,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(818); + var sourcemaps = __webpack_require__(825); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -90563,7 +92942,7 @@ module.exports = Compiler; /***/ }), -/* 791 */ +/* 798 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90576,7 +92955,7 @@ module.exports = Compiler; -var utils = __webpack_require__(792); +var utils = __webpack_require__(799); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -90691,7 +93070,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 792 */ +/* 799 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90705,8 +93084,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(722); -utils.isObject = __webpack_require__(740); +utils.define = __webpack_require__(729); +utils.isObject = __webpack_require__(747); utils.isString = function(val) { @@ -90721,7 +93100,7 @@ module.exports = utils; /***/ }), -/* 793 */ +/* 800 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -90730,14 +93109,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(794); + module.exports = __webpack_require__(801); } else { - module.exports = __webpack_require__(797); + module.exports = __webpack_require__(804); } /***/ }), -/* 794 */ +/* 801 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -90746,7 +93125,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(795); +exports = module.exports = __webpack_require__(802); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -90928,7 +93307,7 @@ function localstorage() { /***/ }), -/* 795 */ +/* 802 */ /***/ (function(module, exports, __webpack_require__) { @@ -90944,7 +93323,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(796); +exports.humanize = __webpack_require__(803); /** * The currently active debug mode names, and names to skip. @@ -91136,7 +93515,7 @@ function coerce(val) { /***/ }), -/* 796 */ +/* 803 */ /***/ (function(module, exports) { /** @@ -91294,7 +93673,7 @@ function plural(ms, n, name) { /***/ }), -/* 797 */ +/* 804 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -91310,7 +93689,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(795); +exports = module.exports = __webpack_require__(802); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -91489,7 +93868,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(798); + var net = __webpack_require__(805); stream = new net.Socket({ fd: fd, readable: false, @@ -91548,13 +93927,13 @@ exports.enable(load()); /***/ }), -/* 798 */ +/* 805 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 799 */ +/* 806 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91564,9 +93943,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(730); -exports.SourceMap = __webpack_require__(800); -exports.sourceMapResolve = __webpack_require__(811); +exports.extend = __webpack_require__(737); +exports.SourceMap = __webpack_require__(807); +exports.sourceMapResolve = __webpack_require__(818); /** * Convert backslash in the given string to forward slashes @@ -91609,7 +93988,7 @@ exports.last = function(arr, n) { /***/ }), -/* 800 */ +/* 807 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -91617,13 +93996,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__(801).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(807).SourceMapConsumer; -exports.SourceNode = __webpack_require__(810).SourceNode; +exports.SourceMapGenerator = __webpack_require__(808).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(814).SourceMapConsumer; +exports.SourceNode = __webpack_require__(817).SourceNode; /***/ }), -/* 801 */ +/* 808 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -91633,10 +94012,10 @@ exports.SourceNode = __webpack_require__(810).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(802); -var util = __webpack_require__(804); -var ArraySet = __webpack_require__(805).ArraySet; -var MappingList = __webpack_require__(806).MappingList; +var base64VLQ = __webpack_require__(809); +var util = __webpack_require__(811); +var ArraySet = __webpack_require__(812).ArraySet; +var MappingList = __webpack_require__(813).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -92045,7 +94424,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 802 */ +/* 809 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92085,7 +94464,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(803); +var base64 = __webpack_require__(810); // 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, @@ -92191,7 +94570,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 803 */ +/* 810 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92264,7 +94643,7 @@ exports.decode = function (charCode) { /***/ }), -/* 804 */ +/* 811 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92687,7 +95066,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 805 */ +/* 812 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92697,7 +95076,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(804); +var util = __webpack_require__(811); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -92814,7 +95193,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 806 */ +/* 813 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92824,7 +95203,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(804); +var util = __webpack_require__(811); /** * Determine whether mappingB is after mappingA with respect to generated @@ -92899,7 +95278,7 @@ exports.MappingList = MappingList; /***/ }), -/* 807 */ +/* 814 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92909,11 +95288,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(804); -var binarySearch = __webpack_require__(808); -var ArraySet = __webpack_require__(805).ArraySet; -var base64VLQ = __webpack_require__(802); -var quickSort = __webpack_require__(809).quickSort; +var util = __webpack_require__(811); +var binarySearch = __webpack_require__(815); +var ArraySet = __webpack_require__(812).ArraySet; +var base64VLQ = __webpack_require__(809); +var quickSort = __webpack_require__(816).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -93987,7 +96366,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 808 */ +/* 815 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94104,7 +96483,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 809 */ +/* 816 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94224,7 +96603,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 810 */ +/* 817 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94234,8 +96613,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(801).SourceMapGenerator; -var util = __webpack_require__(804); +var SourceMapGenerator = __webpack_require__(808).SourceMapGenerator; +var util = __webpack_require__(811); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -94643,17 +97022,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 811 */ +/* 818 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(812) -var resolveUrl = __webpack_require__(813) -var decodeUriComponent = __webpack_require__(814) -var urix = __webpack_require__(816) -var atob = __webpack_require__(817) +var sourceMappingURL = __webpack_require__(819) +var resolveUrl = __webpack_require__(820) +var decodeUriComponent = __webpack_require__(821) +var urix = __webpack_require__(823) +var atob = __webpack_require__(824) @@ -94951,7 +97330,7 @@ module.exports = { /***/ }), -/* 812 */ +/* 819 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -95014,7 +97393,7 @@ void (function(root, factory) { /***/ }), -/* 813 */ +/* 820 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -95032,13 +97411,13 @@ module.exports = resolveUrl /***/ }), -/* 814 */ +/* 821 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(815) +var decodeUriComponent = __webpack_require__(822) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -95049,7 +97428,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 815 */ +/* 822 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95150,7 +97529,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 816 */ +/* 823 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -95173,7 +97552,7 @@ module.exports = urix /***/ }), -/* 817 */ +/* 824 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95187,7 +97566,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 818 */ +/* 825 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95195,8 +97574,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(23); var path = __webpack_require__(16); -var define = __webpack_require__(722); -var utils = __webpack_require__(799); +var define = __webpack_require__(729); +var utils = __webpack_require__(806); /** * Expose `mixin()`. @@ -95339,19 +97718,19 @@ exports.comment = function(node) { /***/ }), -/* 819 */ +/* 826 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(791); +var use = __webpack_require__(798); var util = __webpack_require__(29); -var Cache = __webpack_require__(820); -var define = __webpack_require__(722); -var debug = __webpack_require__(793)('snapdragon:parser'); -var Position = __webpack_require__(821); -var utils = __webpack_require__(799); +var Cache = __webpack_require__(827); +var define = __webpack_require__(729); +var debug = __webpack_require__(800)('snapdragon:parser'); +var Position = __webpack_require__(828); +var utils = __webpack_require__(806); /** * Create a new `Parser` with the given `input` and `options`. @@ -95879,7 +98258,7 @@ module.exports = Parser; /***/ }), -/* 820 */ +/* 827 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95986,13 +98365,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 821 */ +/* 828 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(722); +var define = __webpack_require__(729); /** * Store position for a node @@ -96007,16 +98386,16 @@ module.exports = function Position(start, parser) { /***/ }), -/* 822 */ +/* 829 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(823); -var define = __webpack_require__(829); -var extend = __webpack_require__(830); -var not = __webpack_require__(832); +var safe = __webpack_require__(830); +var define = __webpack_require__(836); +var extend = __webpack_require__(837); +var not = __webpack_require__(839); var MAX_LENGTH = 1024 * 64; /** @@ -96169,10 +98548,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 823 */ +/* 830 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(824); +var parse = __webpack_require__(831); var types = parse.types; module.exports = function (re, opts) { @@ -96218,13 +98597,13 @@ function isRegExp (x) { /***/ }), -/* 824 */ +/* 831 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(825); -var types = __webpack_require__(826); -var sets = __webpack_require__(827); -var positions = __webpack_require__(828); +var util = __webpack_require__(832); +var types = __webpack_require__(833); +var sets = __webpack_require__(834); +var positions = __webpack_require__(835); module.exports = function(regexpStr) { @@ -96506,11 +98885,11 @@ module.exports.types = types; /***/ }), -/* 825 */ +/* 832 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(826); -var sets = __webpack_require__(827); +var types = __webpack_require__(833); +var sets = __webpack_require__(834); // All of these are private and only used by randexp. @@ -96623,7 +99002,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 826 */ +/* 833 */ /***/ (function(module, exports) { module.exports = { @@ -96639,10 +99018,10 @@ module.exports = { /***/ }), -/* 827 */ +/* 834 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(826); +var types = __webpack_require__(833); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -96727,10 +99106,10 @@ exports.anyChar = function() { /***/ }), -/* 828 */ +/* 835 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(826); +var types = __webpack_require__(833); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -96750,7 +99129,7 @@ exports.end = function() { /***/ }), -/* 829 */ +/* 836 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96763,8 +99142,8 @@ exports.end = function() { -var isobject = __webpack_require__(740); -var isDescriptor = __webpack_require__(752); +var isobject = __webpack_require__(747); +var isDescriptor = __webpack_require__(759); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -96795,14 +99174,14 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 830 */ +/* 837 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(831); -var assignSymbols = __webpack_require__(741); +var isExtendable = __webpack_require__(838); +var assignSymbols = __webpack_require__(748); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -96862,7 +99241,7 @@ function isEnum(obj, key) { /***/ }), -/* 831 */ +/* 838 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96875,7 +99254,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(739); +var isPlainObject = __webpack_require__(746); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -96883,14 +99262,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 832 */ +/* 839 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(830); -var safe = __webpack_require__(823); +var extend = __webpack_require__(837); +var safe = __webpack_require__(830); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -96962,14 +99341,14 @@ module.exports = toRegex; /***/ }), -/* 833 */ +/* 840 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(834); -var extglob = __webpack_require__(849); +var nanomatch = __webpack_require__(841); +var extglob = __webpack_require__(856); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -97046,7 +99425,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 834 */ +/* 841 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97057,17 +99436,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(29); -var toRegex = __webpack_require__(721); -var extend = __webpack_require__(835); +var toRegex = __webpack_require__(728); +var extend = __webpack_require__(842); /** * Local dependencies */ -var compilers = __webpack_require__(837); -var parsers = __webpack_require__(838); -var cache = __webpack_require__(841); -var utils = __webpack_require__(843); +var compilers = __webpack_require__(844); +var parsers = __webpack_require__(845); +var cache = __webpack_require__(848); +var utils = __webpack_require__(850); var MAX_LENGTH = 1024 * 64; /** @@ -97891,14 +100270,14 @@ module.exports = nanomatch; /***/ }), -/* 835 */ +/* 842 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(836); -var assignSymbols = __webpack_require__(741); +var isExtendable = __webpack_require__(843); +var assignSymbols = __webpack_require__(748); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -97958,7 +100337,7 @@ function isEnum(obj, key) { /***/ }), -/* 836 */ +/* 843 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97971,7 +100350,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(739); +var isPlainObject = __webpack_require__(746); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -97979,7 +100358,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 837 */ +/* 844 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98325,15 +100704,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 838 */ +/* 845 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(732); -var toRegex = __webpack_require__(721); -var isOdd = __webpack_require__(839); +var regexNot = __webpack_require__(739); +var toRegex = __webpack_require__(728); +var isOdd = __webpack_require__(846); /** * Characters to use in negation regex (we want to "not" match @@ -98719,7 +101098,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 839 */ +/* 846 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98732,7 +101111,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(840); +var isNumber = __webpack_require__(847); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -98746,7 +101125,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 840 */ +/* 847 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98774,14 +101153,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 841 */ +/* 848 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(842))(); +module.exports = new (__webpack_require__(849))(); /***/ }), -/* 842 */ +/* 849 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98794,7 +101173,7 @@ module.exports = new (__webpack_require__(842))(); -var MapCache = __webpack_require__(820); +var MapCache = __webpack_require__(827); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -98916,7 +101295,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 843 */ +/* 850 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98929,14 +101308,14 @@ var path = __webpack_require__(16); * Module dependencies */ -var isWindows = __webpack_require__(844)(); -var Snapdragon = __webpack_require__(760); -utils.define = __webpack_require__(845); -utils.diff = __webpack_require__(846); -utils.extend = __webpack_require__(835); -utils.pick = __webpack_require__(847); -utils.typeOf = __webpack_require__(848); -utils.unique = __webpack_require__(733); +var isWindows = __webpack_require__(851)(); +var Snapdragon = __webpack_require__(767); +utils.define = __webpack_require__(852); +utils.diff = __webpack_require__(853); +utils.extend = __webpack_require__(842); +utils.pick = __webpack_require__(854); +utils.typeOf = __webpack_require__(855); +utils.unique = __webpack_require__(740); /** * Returns true if the given value is effectively an empty string @@ -99302,7 +101681,7 @@ utils.unixify = function(options) { /***/ }), -/* 844 */ +/* 851 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -99330,7 +101709,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 845 */ +/* 852 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99343,8 +101722,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(740); -var isDescriptor = __webpack_require__(752); +var isobject = __webpack_require__(747); +var isDescriptor = __webpack_require__(759); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -99375,7 +101754,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 846 */ +/* 853 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99429,7 +101808,7 @@ function diffArray(one, two) { /***/ }), -/* 847 */ +/* 854 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99442,7 +101821,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(740); +var isObject = __webpack_require__(747); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -99471,7 +101850,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 848 */ +/* 855 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -99606,7 +101985,7 @@ function isBuffer(val) { /***/ }), -/* 849 */ +/* 856 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99616,18 +101995,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(730); -var unique = __webpack_require__(733); -var toRegex = __webpack_require__(721); +var extend = __webpack_require__(737); +var unique = __webpack_require__(740); +var toRegex = __webpack_require__(728); /** * Local dependencies */ -var compilers = __webpack_require__(850); -var parsers = __webpack_require__(861); -var Extglob = __webpack_require__(864); -var utils = __webpack_require__(863); +var compilers = __webpack_require__(857); +var parsers = __webpack_require__(868); +var Extglob = __webpack_require__(871); +var utils = __webpack_require__(870); var MAX_LENGTH = 1024 * 64; /** @@ -99944,13 +102323,13 @@ module.exports = extglob; /***/ }), -/* 850 */ +/* 857 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(851); +var brackets = __webpack_require__(858); /** * Extglob compilers @@ -100120,7 +102499,7 @@ module.exports = function(extglob) { /***/ }), -/* 851 */ +/* 858 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100130,17 +102509,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(852); -var parsers = __webpack_require__(854); +var compilers = __webpack_require__(859); +var parsers = __webpack_require__(861); /** * Module dependencies */ -var debug = __webpack_require__(856)('expand-brackets'); -var extend = __webpack_require__(730); -var Snapdragon = __webpack_require__(760); -var toRegex = __webpack_require__(721); +var debug = __webpack_require__(863)('expand-brackets'); +var extend = __webpack_require__(737); +var Snapdragon = __webpack_require__(767); +var toRegex = __webpack_require__(728); /** * Parses the given POSIX character class `pattern` and returns a @@ -100338,13 +102717,13 @@ module.exports = brackets; /***/ }), -/* 852 */ +/* 859 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(853); +var posix = __webpack_require__(860); module.exports = function(brackets) { brackets.compiler @@ -100432,7 +102811,7 @@ module.exports = function(brackets) { /***/ }), -/* 853 */ +/* 860 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100461,14 +102840,14 @@ module.exports = { /***/ }), -/* 854 */ +/* 861 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(855); -var define = __webpack_require__(722); +var utils = __webpack_require__(862); +var define = __webpack_require__(729); /** * Text regex @@ -100687,14 +103066,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 855 */ +/* 862 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(721); -var regexNot = __webpack_require__(732); +var toRegex = __webpack_require__(728); +var regexNot = __webpack_require__(739); var cached; /** @@ -100728,7 +103107,7 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 856 */ +/* 863 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -100737,14 +103116,14 @@ exports.createRegex = function(pattern, include) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(857); + module.exports = __webpack_require__(864); } else { - module.exports = __webpack_require__(860); + module.exports = __webpack_require__(867); } /***/ }), -/* 857 */ +/* 864 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -100753,7 +103132,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(858); +exports = module.exports = __webpack_require__(865); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -100935,7 +103314,7 @@ function localstorage() { /***/ }), -/* 858 */ +/* 865 */ /***/ (function(module, exports, __webpack_require__) { @@ -100951,7 +103330,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(859); +exports.humanize = __webpack_require__(866); /** * The currently active debug mode names, and names to skip. @@ -101143,7 +103522,7 @@ function coerce(val) { /***/ }), -/* 859 */ +/* 866 */ /***/ (function(module, exports) { /** @@ -101301,7 +103680,7 @@ function plural(ms, n, name) { /***/ }), -/* 860 */ +/* 867 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -101317,7 +103696,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(858); +exports = module.exports = __webpack_require__(865); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -101496,7 +103875,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(798); + var net = __webpack_require__(805); stream = new net.Socket({ fd: fd, readable: false, @@ -101555,15 +103934,15 @@ exports.enable(load()); /***/ }), -/* 861 */ +/* 868 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(851); -var define = __webpack_require__(862); -var utils = __webpack_require__(863); +var brackets = __webpack_require__(858); +var define = __webpack_require__(869); +var utils = __webpack_require__(870); /** * Characters to use in text regex (we want to "not" match @@ -101718,7 +104097,7 @@ module.exports = parsers; /***/ }), -/* 862 */ +/* 869 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101731,7 +104110,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(752); +var isDescriptor = __webpack_require__(759); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -101756,14 +104135,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 863 */ +/* 870 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(732); -var Cache = __webpack_require__(842); +var regex = __webpack_require__(739); +var Cache = __webpack_require__(849); /** * Utils @@ -101832,7 +104211,7 @@ utils.createRegex = function(str) { /***/ }), -/* 864 */ +/* 871 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101842,16 +104221,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(760); -var define = __webpack_require__(862); -var extend = __webpack_require__(730); +var Snapdragon = __webpack_require__(767); +var define = __webpack_require__(869); +var extend = __webpack_require__(737); /** * Local dependencies */ -var compilers = __webpack_require__(850); -var parsers = __webpack_require__(861); +var compilers = __webpack_require__(857); +var parsers = __webpack_require__(868); /** * Customize Snapdragon parser and renderer @@ -101917,16 +104296,16 @@ module.exports = Extglob; /***/ }), -/* 865 */ +/* 872 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(849); -var nanomatch = __webpack_require__(834); -var regexNot = __webpack_require__(732); -var toRegex = __webpack_require__(822); +var extglob = __webpack_require__(856); +var nanomatch = __webpack_require__(841); +var regexNot = __webpack_require__(739); +var toRegex = __webpack_require__(829); var not; /** @@ -102007,14 +104386,14 @@ function textRegex(pattern) { /***/ }), -/* 866 */ +/* 873 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(842))(); +module.exports = new (__webpack_require__(849))(); /***/ }), -/* 867 */ +/* 874 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102027,13 +104406,13 @@ var path = __webpack_require__(16); * Module dependencies */ -var Snapdragon = __webpack_require__(760); -utils.define = __webpack_require__(829); -utils.diff = __webpack_require__(846); -utils.extend = __webpack_require__(830); -utils.pick = __webpack_require__(847); -utils.typeOf = __webpack_require__(868); -utils.unique = __webpack_require__(733); +var Snapdragon = __webpack_require__(767); +utils.define = __webpack_require__(836); +utils.diff = __webpack_require__(853); +utils.extend = __webpack_require__(837); +utils.pick = __webpack_require__(854); +utils.typeOf = __webpack_require__(875); +utils.unique = __webpack_require__(740); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -102330,7 +104709,7 @@ utils.unixify = function(options) { /***/ }), -/* 868 */ +/* 875 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -102465,7 +104844,7 @@ function isBuffer(val) { /***/ }), -/* 869 */ +/* 876 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102484,9 +104863,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(870); -var reader_1 = __webpack_require__(883); -var fs_stream_1 = __webpack_require__(887); +var readdir = __webpack_require__(877); +var reader_1 = __webpack_require__(890); +var fs_stream_1 = __webpack_require__(894); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -102547,15 +104926,15 @@ exports.default = ReaderAsync; /***/ }), -/* 870 */ +/* 877 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(871); -const readdirAsync = __webpack_require__(879); -const readdirStream = __webpack_require__(882); +const readdirSync = __webpack_require__(878); +const readdirAsync = __webpack_require__(886); +const readdirStream = __webpack_require__(889); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -102639,7 +105018,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 871 */ +/* 878 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102647,11 +105026,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(872); +const DirectoryReader = __webpack_require__(879); let syncFacade = { - fs: __webpack_require__(877), - forEach: __webpack_require__(878), + fs: __webpack_require__(884), + forEach: __webpack_require__(885), sync: true }; @@ -102680,7 +105059,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 872 */ +/* 879 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102689,9 +105068,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(27).Readable; const EventEmitter = __webpack_require__(379).EventEmitter; const path = __webpack_require__(16); -const normalizeOptions = __webpack_require__(873); -const stat = __webpack_require__(875); -const call = __webpack_require__(876); +const normalizeOptions = __webpack_require__(880); +const stat = __webpack_require__(882); +const call = __webpack_require__(883); /** * Asynchronously reads the contents of a directory and streams the results @@ -103067,14 +105446,14 @@ module.exports = DirectoryReader; /***/ }), -/* 873 */ +/* 880 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(874); +const globToRegExp = __webpack_require__(881); module.exports = normalizeOptions; @@ -103251,7 +105630,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 874 */ +/* 881 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -103388,13 +105767,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 875 */ +/* 882 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(876); +const call = __webpack_require__(883); module.exports = stat; @@ -103469,7 +105848,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 876 */ +/* 883 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103530,14 +105909,14 @@ function callOnce (fn) { /***/ }), -/* 877 */ +/* 884 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const call = __webpack_require__(876); +const call = __webpack_require__(883); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -103601,7 +105980,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 878 */ +/* 885 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103630,7 +106009,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 879 */ +/* 886 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103638,12 +106017,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(880); -const DirectoryReader = __webpack_require__(872); +const maybe = __webpack_require__(887); +const DirectoryReader = __webpack_require__(879); let asyncFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(881), + forEach: __webpack_require__(888), async: true }; @@ -103685,7 +106064,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 880 */ +/* 887 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103712,7 +106091,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 881 */ +/* 888 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103748,7 +106127,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 882 */ +/* 889 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103756,11 +106135,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(872); +const DirectoryReader = __webpack_require__(879); let streamFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(881), + forEach: __webpack_require__(888), async: true }; @@ -103780,16 +106159,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 883 */ +/* 890 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var deep_1 = __webpack_require__(884); -var entry_1 = __webpack_require__(886); -var pathUtil = __webpack_require__(885); +var deep_1 = __webpack_require__(891); +var entry_1 = __webpack_require__(893); +var pathUtil = __webpack_require__(892); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -103855,14 +106234,14 @@ exports.default = Reader; /***/ }), -/* 884 */ +/* 891 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(885); -var patternUtils = __webpack_require__(714); +var pathUtils = __webpack_require__(892); +var patternUtils = __webpack_require__(721); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -103945,7 +106324,7 @@ exports.default = DeepFilter; /***/ }), -/* 885 */ +/* 892 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103976,14 +106355,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 886 */ +/* 893 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(885); -var patternUtils = __webpack_require__(714); +var pathUtils = __webpack_require__(892); +var patternUtils = __webpack_require__(721); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -104068,7 +106447,7 @@ exports.default = EntryFilter; /***/ }), -/* 887 */ +/* 894 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104088,8 +106467,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(27); -var fsStat = __webpack_require__(888); -var fs_1 = __webpack_require__(892); +var fsStat = __webpack_require__(895); +var fs_1 = __webpack_require__(899); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -104139,14 +106518,14 @@ exports.default = FileSystemStream; /***/ }), -/* 888 */ +/* 895 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(889); -const statProvider = __webpack_require__(891); +const optionsManager = __webpack_require__(896); +const statProvider = __webpack_require__(898); /** * Asynchronous API. */ @@ -104177,13 +106556,13 @@ exports.statSync = statSync; /***/ }), -/* 889 */ +/* 896 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(890); +const fsAdapter = __webpack_require__(897); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -104196,7 +106575,7 @@ exports.prepare = prepare; /***/ }), -/* 890 */ +/* 897 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104219,7 +106598,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 891 */ +/* 898 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104271,7 +106650,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 892 */ +/* 899 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104302,7 +106681,7 @@ exports.default = FileSystem; /***/ }), -/* 893 */ +/* 900 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104322,9 +106701,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(27); -var readdir = __webpack_require__(870); -var reader_1 = __webpack_require__(883); -var fs_stream_1 = __webpack_require__(887); +var readdir = __webpack_require__(877); +var reader_1 = __webpack_require__(890); +var fs_stream_1 = __webpack_require__(894); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -104392,7 +106771,7 @@ exports.default = ReaderStream; /***/ }), -/* 894 */ +/* 901 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104411,9 +106790,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(870); -var reader_1 = __webpack_require__(883); -var fs_sync_1 = __webpack_require__(895); +var readdir = __webpack_require__(877); +var reader_1 = __webpack_require__(890); +var fs_sync_1 = __webpack_require__(902); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -104473,7 +106852,7 @@ exports.default = ReaderSync; /***/ }), -/* 895 */ +/* 902 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104492,8 +106871,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(888); -var fs_1 = __webpack_require__(892); +var fsStat = __webpack_require__(895); +var fs_1 = __webpack_require__(899); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -104539,7 +106918,7 @@ exports.default = FileSystemSync; /***/ }), -/* 896 */ +/* 903 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104555,7 +106934,7 @@ exports.flatten = flatten; /***/ }), -/* 897 */ +/* 904 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104576,13 +106955,13 @@ exports.merge = merge; /***/ }), -/* 898 */ +/* 905 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(899); +const pathType = __webpack_require__(906); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -104648,13 +107027,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 899 */ +/* 906 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(900); +const pify = __webpack_require__(907); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -104697,7 +107076,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 900 */ +/* 907 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104788,17 +107167,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 901 */ +/* 908 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); const path = __webpack_require__(16); -const fastGlob = __webpack_require__(710); -const gitIgnore = __webpack_require__(902); -const pify = __webpack_require__(903); -const slash = __webpack_require__(904); +const fastGlob = __webpack_require__(717); +const gitIgnore = __webpack_require__(909); +const pify = __webpack_require__(910); +const slash = __webpack_require__(911); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -104896,7 +107275,7 @@ module.exports.sync = options => { /***/ }), -/* 902 */ +/* 909 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -105365,7 +107744,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 903 */ +/* 910 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105440,7 +107819,7 @@ module.exports = (input, options) => { /***/ }), -/* 904 */ +/* 911 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105458,17 +107837,17 @@ module.exports = input => { /***/ }), -/* 905 */ +/* 912 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); const {constants: fsConstants} = __webpack_require__(23); -const {Buffer} = __webpack_require__(906); -const CpFileError = __webpack_require__(907); -const fs = __webpack_require__(909); -const ProgressEmitter = __webpack_require__(911); +const {Buffer} = __webpack_require__(913); +const CpFileError = __webpack_require__(914); +const fs = __webpack_require__(918); +const ProgressEmitter = __webpack_require__(920); const cpFile = (source, destination, options) => { if (!source || !destination) { @@ -105622,7 +108001,7 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 906 */ +/* 913 */ /***/ (function(module, exports, __webpack_require__) { /* eslint-disable node/no-deprecated-api */ @@ -105690,12 +108069,12 @@ SafeBuffer.allocUnsafeSlow = function (size) { /***/ }), -/* 907 */ +/* 914 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(908); +const NestedError = __webpack_require__(915); class CpFileError extends NestedError { constructor(message, nested) { @@ -105709,10 +108088,10 @@ module.exports = CpFileError; /***/ }), -/* 908 */ +/* 915 */ /***/ (function(module, exports, __webpack_require__) { -var inherits = __webpack_require__(509); +var inherits = __webpack_require__(916); var NestedError = function (message, nested) { this.nested = nested; @@ -105763,15 +108142,57 @@ module.exports = NestedError; /***/ }), -/* 909 */ +/* 916 */ +/***/ (function(module, exports, __webpack_require__) { + +try { + var util = __webpack_require__(29); + if (typeof util.inherits !== 'function') throw ''; + module.exports = util.inherits; +} catch (e) { + module.exports = __webpack_require__(917); +} + + +/***/ }), +/* 917 */ +/***/ (function(module, exports) { + +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + + +/***/ }), +/* 918 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(22); const makeDir = __webpack_require__(559); -const pify = __webpack_require__(910); -const CpFileError = __webpack_require__(907); +const pify = __webpack_require__(919); +const CpFileError = __webpack_require__(914); const fsP = pify(fs); @@ -105916,7 +108337,7 @@ if (fs.copyFileSync) { /***/ }), -/* 910 */ +/* 919 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105991,7 +108412,7 @@ module.exports = (input, options) => { /***/ }), -/* 911 */ +/* 920 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106032,12 +108453,12 @@ module.exports = ProgressEmitter; /***/ }), -/* 912 */ +/* 921 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(913); +const NestedError = __webpack_require__(922); class CpyError extends NestedError { constructor(message, nested) { @@ -106051,7 +108472,7 @@ module.exports = CpyError; /***/ }), -/* 913 */ +/* 922 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(29).inherits; @@ -106107,7 +108528,7 @@ module.exports = NestedError; /***/ }), -/* 914 */ +/* 923 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; diff --git a/packages/kbn-pm/src/utils/scripts.ts b/packages/kbn-pm/src/utils/scripts.ts index f12aeddec9163..009efa1285c0c 100644 --- a/packages/kbn-pm/src/utils/scripts.ts +++ b/packages/kbn-pm/src/utils/scripts.ts @@ -67,11 +67,14 @@ export function runScriptInPackageStreaming(script: string, args: string[], pkg: } export async function yarnWorkspacesInfo(directory: string): Promise { - const workspacesInfo = await spawn('yarn', ['workspaces', 'info', '--json'], { + const { stdout } = await spawn('yarn', ['--json', 'workspaces', 'info'], { cwd: directory, stdio: 'pipe', }); - const stdout = JSON.parse(workspacesInfo.stdout); - return JSON.parse(stdout.data); + try { + return JSON.parse(JSON.parse(stdout).data); + } catch (error) { + throw new Error(`'yarn workspaces info --json' produced unexpected output: \n${stdout}`); + } } diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index ea15d2e34ea3a..fc9d159ea9b95 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -9,12 +9,12 @@ "kbn:watch": "node scripts/build --watch" }, "devDependencies": { + "@elastic/charts": "^17.0.2", + "abort-controller": "^3.0.0", "@elastic/eui": "18.3.0", - "@elastic/charts": "^16.1.0", "@kbn/dev-utils": "1.0.0", "@kbn/i18n": "1.0.0", "@yarnpkg/lockfile": "^1.1.0", - "abortcontroller-polyfill": "^1.3.0", "angular": "^1.7.9", "core-js": "^3.2.1", "css-loader": "^2.1.1", @@ -24,13 +24,13 @@ "mini-css-extract-plugin": "0.8.0", "moment": "^2.24.0", "moment-timezone": "^0.5.27", + "react": "^16.12.0", "react-dom": "^16.12.0", "react-intl": "^2.8.0", - "react": "^16.12.0", "read-pkg": "^5.2.0", "regenerator-runtime": "^0.13.3", "symbol-observable": "^1.2.0", "webpack": "4.41.0", "whatwg-fetch": "^3.0.0" } -} \ No newline at end of file +} diff --git a/packages/kbn-ui-shared-deps/polyfills.js b/packages/kbn-ui-shared-deps/polyfills.js index d2305d643e4d2..612fbb9a78b50 100644 --- a/packages/kbn-ui-shared-deps/polyfills.js +++ b/packages/kbn-ui-shared-deps/polyfills.js @@ -21,6 +21,6 @@ require('core-js/stable'); require('regenerator-runtime/runtime'); require('custom-event-polyfill'); require('whatwg-fetch'); -require('abortcontroller-polyfill/dist/polyfill-patch-fetch'); +require('abort-controller/polyfill'); require('./vendor/childnode_remove_polyfill'); require('symbol-observable'); diff --git a/rfcs/text/0006_management_section_service.md b/rfcs/text/0006_management_section_service.md index d9781e85cd8a9..1a52e85a4ff16 100644 --- a/rfcs/text/0006_management_section_service.md +++ b/rfcs/text/0006_management_section_service.md @@ -257,15 +257,7 @@ Current public contracts owned by the legacy service: ```js // ui/management/index interface API { - PAGE_TITLE_COMPONENT: string; // actually related to advanced settings? - PAGE_SUBTITLE_COMPONENT: string; // actually related to advanced settings? - PAGE_FOOTER_COMPONENT: string; // actually related to advanced settings? SidebarNav: React.FC; - registerSettingsComponent: ( - id: string, - component: string | React.FC, - allowOverride: boolean - ) => void; management: new ManagementSection(); MANAGEMENT_BREADCRUMB: { text: string; diff --git a/src/core/TESTING.md b/src/core/TESTING.md index 23c0879e4411e..4dfab8830a506 100644 --- a/src/core/TESTING.md +++ b/src/core/TESTING.md @@ -548,9 +548,300 @@ _How to test SO operations_ _How to test ES clients_ -## Plugin Integrations +## Plugin integrations -_How to test against specific plugin APIs (eg. data plugin)_ +In the new platform, all plugin's dependencies to other plugins are explicitly declared in their `kibana.json` +manifest. As for `core`, the dependencies `setup` and `start` contracts are injected in your plugin's respective +`setup` and `start` phases. One of the upsides with testing is that every usage of the dependencies is explicit, +and that the plugin's contracts must be propagated to the parts of the code using them, meaning that isolating a +specific logical component for unit testing is way easier than in legacy. + +The approach to test parts of a plugin's code that is relying on other plugins is quite similar to testing +code using `core` APIs: it's expected to mock the dependency, and make it return the value the test is expecting. + +Most plugins are defining mocks for their contracts. The convention is to expose them in a `mocks` file in +`my_plugin/server` and/or `my_plugin/public`. For example for the `data` plugin, the client-side mocks are located in +`src/plugins/data/public/mocks.ts`. When such mocks are present, it's strongly recommended to use them +when testing against dependencies. Otherwise, one should create it's own mocked implementation of the dependency's +contract (and should probably ping the plugin's owner to ask them to add proper contract mocks). + +### Preconditions + +For these examples, we are going to see how we should test the `myPlugin` plugin. + +This plugin declares the `data` plugin as a `required` dependency and the `usageCollection` plugin as an `optional` +one. It also exposes a `getSpecialSuggestions` API in it's start contract, which relies on the `data` plugin to retrieve +data. + +`MyPlugin` plugin definition: + +```typescript +// src/plugins/myplugin/public/plugin.ts +import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { DataPublicPluginSetup, DataPublicPluginStart } from '../../data/public'; +import { UsageCollectionSetup } from '../../usage_collection/public'; +import { SuggestionsService } from './suggestions'; + +interface MyPluginSetupDeps { + data: DataPublicPluginSetup; + usageCollection?: UsageCollectionSetup; +} + +interface MyPluginStartDeps { + data: DataPublicPluginStart; +} + +export class MyPlugin implements Plugin { + private suggestionsService = new SuggestionsService(); + + public setup(core: CoreSetup, { data, usageCollection }: MyPluginSetupDeps) { + // setup our internal service + this.suggestionsService.setup(data); + + // an example on using an optional dependency that will be tested + if (usageCollection) { + usageCollection.allowTrackUserAgent(true); + } + + return {}; + } + + public start(core: CoreStart, { data }: MyPluginStartDeps) { + const suggestions = this.suggestionsService.start(data); + return { + getSpecialSuggestions: (query: string) => suggestions.getSuggestions(query), + }; + } + + public stop() {} +} + +export type MyPluginSetup = ReturnType; +export type MyPluginStart = ReturnType; +``` + +The underlying `SuggestionsService` implementation: + +```typescript +// src/plugins/myplugin/public/suggestions/suggestion_service.ts +import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../data/public'; + +// stubs for testing purposes +const suggestDependingOn = (...args: any[]) => []; +const baseOptions = {} as any; +export const defaultSuggestions = [ + { + text: 'a default suggestion', + }, +] as any[]; + +export class SuggestionsService { + public setup(data: DataPublicPluginSetup) { + // register a suggestion provider to the `data` dependency plugin + data.autocomplete.addQuerySuggestionProvider('fr', async args => { + return suggestDependingOn(args); + }); + } + + public start(data: DataPublicPluginStart) { + return { + getSuggestions: async (query: string) => { + // use the `data` plugin contract to retrieve arbitrary data + // note: this logic does not really make any sense and is only here to introduce a behavior to test + const baseSuggestions = await data.autocomplete.getQuerySuggestions({ + ...baseOptions, + query, + }); + if (!baseSuggestions || baseSuggestions.length === 0) { + return defaultSuggestions; + } + return baseSuggestions.filter(suggestion => suggestion.type !== 'conjunction'); + }, + }; + } +} +``` + +### Testing dependencies usages + +A plugin should test expected usage and calls on it's dependency plugins' API. + +Some calls, such as 'registration' APIs exposed from dependency plugins, should be checked, +to ensure both that they are actually executed, and performed with the correct parameters. + +For our example plugin's `SuggestionsService`, we should assert that the suggestion provider is correctly +registered to the `data` plugin during the `setup` phase, and that `getSuggestions` calls +`autocomplete.getQuerySuggestions` with the correct parameters. + +```typescript +// src/plugins/myplugin/public/suggestions/suggestion_service.test.ts +import { + dataPluginMock, + Setup as DataPluginSetupMock, + Start as DataPluginStartMock, +} from '../../../data/public/mocks'; +import { SuggestionsService } from './suggestion_service'; + +describe('SuggestionsService', () => { + let service: SuggestionsService; + let dataSetup: DataPluginSetupMock; + let dataStart: DataPluginStartMock; + + beforeEach(() => { + service = new SuggestionsService(); + dataSetup = dataPluginMock.createSetupContract(); + dataStart = dataPluginMock.createStartContract(); + }); + + describe('#setup', () => { + it('registers the query suggestion provider to the data plugin', () => { + service.setup(dataSetup); + + expect(dataSetup.autocomplete.addQuerySuggestionProvider).toHaveBeenCalledTimes(1); + expect(dataSetup.autocomplete.addQuerySuggestionProvider).toHaveBeenCalledWith( + 'fr', + expect.any(Function) + ); + }); + }); + + describe('#start', () => { + describe('#getSuggestions', () => { + it('calls getQuerySuggestions with the correct query', async () => { + service.setup(dataSetup); + const serviceStart = service.start(dataStart); + + await serviceStart.getSuggestions('some query'); + + expect(dataStart.autocomplete.getQuerySuggestions).toHaveBeenCalledTimes(1); + expect(dataStart.autocomplete.getQuerySuggestions).toHaveBeenCalledWith( + expect.objectContaining({ + query: 'some query', + }) + ); + }); + }); + }); +}); +``` + +### Testing components consuming the dependencies + +When testing parts of your plugin code that depends on the dependency plugin's data, the best approach +is to mock the dependency to be able to get the behavior expected for the test. + +In this example, we are going to mock the results of `autocomplete.getQuerySuggestions` to be able to test +the service's `getSuggestions` method. + +```typescript +// src/plugins/myplugin/public/suggestions/suggestion_service.ts + +describe('#start', () => { + describe('#getSuggestions', () => { + it('returns the default suggestions when autocomplete returns no results', async () => { + dataStart.autocomplete.getQuerySuggestions.mockResolvedValue([]); + + service.setup(dataSetup); + const serviceStart = service.start(dataStart); + + const results = await serviceStart.getSuggestions('some query'); + expect(results).toEqual(defaultSuggestions); + }); + + it('excludes conjunctions from the autocomplete results', async () => { + dataStart.autocomplete.getQuerySuggestions.mockResolvedValue([ + { + type: 'field', + text: 'field suggestion', + }, + { + type: 'conjunction', + text: 'conjunction suggestion', + }, + ]); + + service.setup(dataSetup); + const serviceStart = service.start(dataStart); + + const results = await serviceStart.getSuggestions('some query'); + + expect(results).toEqual([ + { + type: 'field', + text: 'field suggestion', + }, + ]); + }); + }); +}); +``` + +### Testing optional plugin dependencies + +Plugins should test that their behavior remains correct when their optional dependencies are either available or not. + +A basic test would be to ensure that the plugin properly initialize without error when the optional +dependency is missing: + +```typescript +// src/plugins/myplugin/public/plugin.test.ts +import { coreMock } from '../../../core/public/mocks'; +import { dataPluginMock } from '../../data/public/mocks'; +import { MyPlugin } from './plugin'; + +describe('Plugin', () => { + it('initializes correctly if usageCollection is disabled', () => { + const plugin = new MyPlugin(coreMock.createPluginInitializerContext()); + const coreSetup = coreMock.createSetup(); + const setupDeps = { + data: dataPluginMock.createSetupContract(), + // optional usageCollector dependency is not available + }; + + const coreStart = coreMock.createStart(); + const startDeps = { + data: dataPluginMock.createStartContract(), + }; + + expect(() => { + plugin.setup(coreSetup, setupDeps); + }).not.toThrow(); + expect(() => { + plugin.start(coreStart, startDeps); + }).not.toThrow(); + }); +}); +``` + +Then we should test that when optional dependency is properly used when present: + +```typescript +// src/plugins/myplugin/public/plugin.test.ts +import { coreMock } from '../../../core/public/mocks'; +import { dataPluginMock } from '../../data/public/mocks'; +import { usageCollectionPluginMock } from '../../usage_collection/public/mocks'; + +import { MyPlugin } from './plugin'; + +describe('Plugin', () => { + // [...] + + it('enables trackUserAgent when usageCollection is available', async () => { + const plugin = new MyPlugin(coreMock.createPluginInitializerContext()); + const coreSetup = coreMock.createSetup(); + const usageCollectionSetup = usageCollectionPluginMock.createSetupContract(); + const setupDeps = { + data: dataPluginMock.createSetupContract(), + usageCollection: usageCollectionSetup, + }; + + plugin.setup(coreSetup, setupDeps); + + expect(usageCollectionSetup.allowTrackUserAgent).toHaveBeenCalledTimes(1); + expect(usageCollectionSetup.allowTrackUserAgent).toHaveBeenCalledWith(true); + }); +}); +``` ## Plugin Contracts diff --git a/src/core/server/index.ts b/src/core/server/index.ts index c45acd7f0129a..cc838ddd1351d 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -197,6 +197,7 @@ export { SavedObjectsImportUnsupportedTypeError, SavedObjectsMigrationLogger, SavedObjectsRawDoc, + SavedObjectSanitizedDoc, SavedObjectsRepositoryFactory, SavedObjectsResolveImportErrorsOptions, SavedObjectsSchema, @@ -211,6 +212,15 @@ export { SavedObjectsRepository, SavedObjectsDeleteByNamespaceOptions, SavedObjectsIncrementCounterOptions, + SavedObjectsComplexFieldMapping, + SavedObjectsCoreFieldMapping, + SavedObjectsFieldMapping, + SavedObjectsTypeMappingDefinition, + SavedObjectsMappingProperties, + SavedObjectTypeRegistry, + SavedObjectsType, + SavedObjectMigrationMap, + SavedObjectMigrationFn, } from './saved_objects'; export { diff --git a/src/core/server/legacy/legacy_service.mock.ts b/src/core/server/legacy/legacy_service.mock.ts index 495141cdcb58d..44405dc391d8e 100644 --- a/src/core/server/legacy/legacy_service.mock.ts +++ b/src/core/server/legacy/legacy_service.mock.ts @@ -18,13 +18,18 @@ */ import { LegacyService } from './legacy_service'; -import { LegacyServiceDiscoverPlugins, LegacyServiceSetupDeps } from './types'; +import { LegacyConfig, LegacyServiceDiscoverPlugins, LegacyServiceSetupDeps } from './types'; type LegacyServiceMock = jest.Mocked & { legacyId: symbol }>; const createDiscoverPluginsMock = (): LegacyServiceDiscoverPlugins => ({ pluginSpecs: [], - uiExports: {} as any, + uiExports: { + savedObjectSchemas: {}, + savedObjectMappings: [], + savedObjectMigrations: {}, + savedObjectValidations: {}, + }, navLinks: [], pluginExtendedConfig: { get: jest.fn(), @@ -34,6 +39,7 @@ const createDiscoverPluginsMock = (): LegacyServiceDiscoverPlugins => ({ disabledPluginSpecs: [], settings: {}, }); + const createLegacyServiceMock = (): LegacyServiceMock => ({ legacyId: Symbol(), discoverPlugins: jest.fn().mockResolvedValue(createDiscoverPluginsMock()), @@ -42,8 +48,15 @@ const createLegacyServiceMock = (): LegacyServiceMock => ({ stop: jest.fn(), }); +const createLegacyConfigMock = (): jest.Mocked => ({ + get: jest.fn(), + has: jest.fn(), + set: jest.fn(), +}); + export const legacyServiceMock = { create: createLegacyServiceMock, createSetupContract: (deps: LegacyServiceSetupDeps) => createLegacyServiceMock().setup(deps), createDiscoverPlugins: createDiscoverPluginsMock, + createLegacyConfig: createLegacyConfigMock, }; diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts index af4db68ee95e1..e8e20580a36db 100644 --- a/src/core/server/legacy/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -83,7 +83,7 @@ beforeEach(() => { getAuthHeaders: () => undefined, } as any, }, - savedObjects: savedObjectsServiceMock.createSetupContract(), + savedObjects: savedObjectsServiceMock.createInternalSetupContract(), plugins: { contracts: new Map([['plugin-id', 'plugin-value']]), uiPlugins: { @@ -101,7 +101,7 @@ beforeEach(() => { startDeps = { core: { capabilities: capabilitiesServiceMock.createStartContract(), - savedObjects: savedObjectsServiceMock.createStartContract(), + savedObjects: savedObjectsServiceMock.createInternalStartContract(), uiSettings: uiSettingsServiceMock.createStartContract(), plugins: { contracts: new Map() }, }, diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index f9b18afadc938..b2501496d87ef 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -262,6 +262,7 @@ export class LegacyService implements CoreService { getScopedClient: startDeps.core.savedObjects.getScopedClient, createScopedRepository: startDeps.core.savedObjects.createScopedRepository, createInternalRepository: startDeps.core.savedObjects.createInternalRepository, + createSerializer: startDeps.core.savedObjects.createSerializer, }, uiSettings: { asScopedToClient: startDeps.core.uiSettings.asScopedToClient }, }; @@ -328,6 +329,7 @@ export class LegacyService implements CoreService { __internals: { hapiServer: setupDeps.core.http.server, kibanaMigrator: startDeps.core.savedObjects.migrator, + typeRegistry: startDeps.core.savedObjects.typeRegistry, uiPlugins: setupDeps.core.plugins.uiPlugins, elasticsearch: setupDeps.core.elasticsearch, rendering: setupDeps.core.rendering, diff --git a/src/core/server/legacy/logging/appenders/__snapshots__/legacy_appender.test.ts.snap b/src/core/server/legacy/logging/appenders/__snapshots__/legacy_appender.test.ts.snap index 6ffc1ea140beb..3c40362e8211e 100644 --- a/src/core/server/legacy/logging/appenders/__snapshots__/legacy_appender.test.ts.snap +++ b/src/core/server/legacy/logging/appenders/__snapshots__/legacy_appender.test.ts.snap @@ -1,127 +1,142 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`\`append()\` correctly pushes records to legacy platform. 1`] = ` -Array [ - Array [ - Object { - "context": "context-1", - "level": LogLevel { - "id": "trace", - "value": 7, - }, - "message": "message-1", - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-2", - "level": LogLevel { - "id": "debug", - "value": 6, - }, - "message": "message-2", - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-3.sub-context-3", - "level": LogLevel { - "id": "info", - "value": 5, - }, - "message": "message-3", - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-4.sub-context-4", - "level": LogLevel { - "id": "warn", - "value": 4, - }, - "message": "message-4", - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-5", - "error": [Error: Some Error], - "level": LogLevel { - "id": "error", - "value": 3, - }, - "message": "message-5-with-error", - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-6", - "level": LogLevel { - "id": "error", - "value": 3, - }, - "message": "message-6-with-message", - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-7.sub-context-7.sub-sub-context-7", - "error": [Error: Some Fatal Error], - "level": LogLevel { - "id": "fatal", - "value": 2, - }, - "message": "message-7-with-error", - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-8.sub-context-8.sub-sub-context-8", - "level": LogLevel { - "id": "fatal", - "value": 2, - }, - "message": "message-8-with-message", - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-9.sub-context-9", - "level": LogLevel { - "id": "info", - "value": 5, - }, - "message": "message-9-with-message", - "meta": Object { - "someValue": 3, - }, - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], - Array [ - Object { - "context": "context-10.sub-context-10", - "level": LogLevel { - "id": "info", - "value": 5, - }, - "message": "message-10-with-message", - "meta": Object { - "tags": Array [ - "tag1", - "tag2", - ], - }, - "timestamp": 2012-02-01T11:22:33.044Z, - }, - ], -] +Object { + "context": "context-1", + "level": LogLevel { + "id": "trace", + "value": 7, + }, + "message": "message-1", + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 2`] = ` +Object { + "context": "context-2", + "level": LogLevel { + "id": "debug", + "value": 6, + }, + "message": "message-2", + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 3`] = ` +Object { + "context": "context-3.sub-context-3", + "level": LogLevel { + "id": "info", + "value": 5, + }, + "message": "message-3", + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 4`] = ` +Object { + "context": "context-4.sub-context-4", + "level": LogLevel { + "id": "warn", + "value": 4, + }, + "message": "message-4", + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 5`] = ` +Object { + "context": "context-5", + "error": [Error: Some Error], + "level": LogLevel { + "id": "error", + "value": 3, + }, + "message": "message-5-with-error", + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 6`] = ` +Object { + "context": "context-6", + "level": LogLevel { + "id": "error", + "value": 3, + }, + "message": "message-6-with-message", + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 7`] = ` +Object { + "context": "context-7.sub-context-7.sub-sub-context-7", + "error": [Error: Some Fatal Error], + "level": LogLevel { + "id": "fatal", + "value": 2, + }, + "message": "message-7-with-error", + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 8`] = ` +Object { + "context": "context-8.sub-context-8.sub-sub-context-8", + "level": LogLevel { + "id": "fatal", + "value": 2, + }, + "message": "message-8-with-message", + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 9`] = ` +Object { + "context": "context-9.sub-context-9", + "level": LogLevel { + "id": "info", + "value": 5, + }, + "message": "message-9-with-message", + "meta": Object { + "someValue": 3, + }, + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} +`; + +exports[`\`append()\` correctly pushes records to legacy platform. 10`] = ` +Object { + "context": "context-10.sub-context-10", + "level": LogLevel { + "id": "info", + "value": 5, + }, + "message": "message-10-with-message", + "meta": Object { + "tags": Array [ + "tag1", + "tag2", + ], + }, + "pid": Any, + "timestamp": 2012-02-01T11:22:33.044Z, +} `; diff --git a/src/core/server/legacy/logging/appenders/legacy_appender.test.ts b/src/core/server/legacy/logging/appenders/legacy_appender.test.ts index adc5dcae3ec9d..538d987e781d0 100644 --- a/src/core/server/legacy/logging/appenders/legacy_appender.test.ts +++ b/src/core/server/legacy/logging/appenders/legacy_appender.test.ts @@ -46,24 +46,28 @@ test('`append()` correctly pushes records to legacy platform.', () => { level: LogLevel.Trace, message: 'message-1', timestamp, + pid: 5355, }, { context: 'context-2', level: LogLevel.Debug, message: 'message-2', timestamp, + pid: 5355, }, { context: 'context-3.sub-context-3', level: LogLevel.Info, message: 'message-3', timestamp, + pid: 5355, }, { context: 'context-4.sub-context-4', level: LogLevel.Warn, message: 'message-4', timestamp, + pid: 5355, }, { context: 'context-5', @@ -71,12 +75,14 @@ test('`append()` correctly pushes records to legacy platform.', () => { level: LogLevel.Error, message: 'message-5-with-error', timestamp, + pid: 5355, }, { context: 'context-6', level: LogLevel.Error, message: 'message-6-with-message', timestamp, + pid: 5355, }, { context: 'context-7.sub-context-7.sub-sub-context-7', @@ -84,18 +90,21 @@ test('`append()` correctly pushes records to legacy platform.', () => { level: LogLevel.Fatal, message: 'message-7-with-error', timestamp, + pid: 5355, }, { context: 'context-8.sub-context-8.sub-sub-context-8', level: LogLevel.Fatal, message: 'message-8-with-message', timestamp, + pid: 5355, }, { context: 'context-9.sub-context-9', level: LogLevel.Info, message: 'message-9-with-message', timestamp, + pid: 5355, meta: { someValue: 3 }, }, { @@ -103,6 +112,7 @@ test('`append()` correctly pushes records to legacy platform.', () => { level: LogLevel.Info, message: 'message-10-with-message', timestamp, + pid: 5355, meta: { tags: ['tag1', 'tag2'] }, }, ]; @@ -113,7 +123,12 @@ test('`append()` correctly pushes records to legacy platform.', () => { } const [mockLegacyLoggingServerInstance] = (LegacyLoggingServer as any).mock.instances; - expect(mockLegacyLoggingServerInstance.log.mock.calls).toMatchSnapshot(); + expect(mockLegacyLoggingServerInstance.log.mock.calls).toHaveLength(records.length); + records.forEach((r, idx) => { + expect(mockLegacyLoggingServerInstance.log.mock.calls[idx][0]).toMatchSnapshot({ + pid: expect.any(Number), + }); + }); }); test('legacy logging server is correctly created and disposed.', async () => { diff --git a/src/core/server/legacy/logging/legacy_logging_server.test.ts b/src/core/server/legacy/logging/legacy_logging_server.test.ts index beb2098600ce6..6dca3a199728e 100644 --- a/src/core/server/legacy/logging/legacy_logging_server.test.ts +++ b/src/core/server/legacy/logging/legacy_logging_server.test.ts @@ -31,6 +31,7 @@ test('correctly forwards log records.', () => { const timestamp = 1554433221100; const firstLogRecord = { timestamp: new Date(timestamp), + pid: 5355, level: LogLevel.Info, context: 'some-context', message: 'some-message', @@ -38,6 +39,7 @@ test('correctly forwards log records.', () => { const secondLogRecord = { timestamp: new Date(timestamp), + pid: 5355, level: LogLevel.Error, context: 'some-context.sub-context', message: 'some-message', @@ -47,6 +49,7 @@ test('correctly forwards log records.', () => { const thirdLogRecord = { timestamp: new Date(timestamp), + pid: 5355, level: LogLevel.Trace, context: 'some-context.sub-context', message: 'some-message', diff --git a/src/core/server/logging/__snapshots__/logging_service.test.ts.snap b/src/core/server/logging/__snapshots__/logging_service.test.ts.snap index ffde6cbcdebd1..54c170f523299 100644 --- a/src/core/server/logging/__snapshots__/logging_service.test.ts.snap +++ b/src/core/server/logging/__snapshots__/logging_service.test.ts.snap @@ -1,57 +1,71 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`appends records via multiple appenders.: console logs 1`] = ` -Array [ - Array [ - "[2012-02-01T00:00:00.000Z][INFO ][some-context] You know, just for your info.", - ], -] -`; +exports[`appends records via multiple appenders.: console logs 1`] = `"[2012-02-01T00:00:00.000Z][INFO ][some-context] You know, just for your info."`; exports[`appends records via multiple appenders.: file logs 1`] = ` -Array [ - Array [ - "[2012-02-01T00:00:00.000Z][WARN ][tests] Config is not ready! -", - ], - Array [ - "[2012-02-01T00:00:00.000Z][ERROR][tests.child] Too bad that config is not ready :/ -", - ], -] +"[2012-02-01T00:00:00.000Z][WARN ][tests] Config is not ready! +" +`; + +exports[`appends records via multiple appenders.: file logs 2`] = ` +"[2012-02-01T00:00:00.000Z][ERROR][tests.child] Too bad that config is not ready :/ +" `; exports[`asLoggerFactory() only allows to create new loggers. 1`] = ` -Array [ - Array [ - "{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"test.context\\",\\"level\\":\\"TRACE\\",\\"message\\":\\"buffered trace message\\"}", - ], - Array [ - "{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"test.context\\",\\"level\\":\\"INFO\\",\\"message\\":\\"buffered info message\\",\\"meta\\":{\\"some\\":\\"value\\"}}", - ], - Array [ - "{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"test.context\\",\\"level\\":\\"FATAL\\",\\"message\\":\\"buffered fatal message\\"}", - ], -] +Object { + "@timestamp": "2012-02-01T00:00:00.000Z", + "context": "test.context", + "level": "TRACE", + "message": "buffered trace message", + "pid": Any, +} +`; + +exports[`asLoggerFactory() only allows to create new loggers. 2`] = ` +Object { + "@timestamp": "2012-02-01T00:00:00.000Z", + "context": "test.context", + "level": "INFO", + "message": "buffered info message", + "meta": Object { + "some": "value", + }, + "pid": Any, +} +`; + +exports[`asLoggerFactory() only allows to create new loggers. 3`] = ` +Object { + "@timestamp": "2012-02-01T00:00:00.000Z", + "context": "test.context", + "level": "FATAL", + "message": "buffered fatal message", + "pid": Any, +} `; exports[`flushes memory buffer logger and switches to real logger once config is provided: buffered messages 1`] = ` -Array [ - Array [ - "{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"test.context\\",\\"level\\":\\"INFO\\",\\"message\\":\\"buffered info message\\",\\"meta\\":{\\"some\\":\\"value\\"}}", - ], - Array [ - "{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"test.context\\",\\"level\\":\\"FATAL\\",\\"message\\":\\"buffered fatal message\\"}", - ], -] +Object { + "@timestamp": "2012-02-01T00:00:00.000Z", + "context": "test.context", + "level": "INFO", + "message": "buffered info message", + "meta": Object { + "some": "value", + }, + "pid": Any, +} `; exports[`flushes memory buffer logger and switches to real logger once config is provided: new messages 1`] = ` -Array [ - Array [ - "{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"test.context\\",\\"level\\":\\"INFO\\",\\"message\\":\\"some new info message\\"}", - ], -] +Object { + "@timestamp": "2012-02-01T00:00:00.000Z", + "context": "test.context", + "level": "INFO", + "message": "some new info message", + "pid": Any, +} `; exports[`uses \`root\` logger if context is not specified. 1`] = ` @@ -63,32 +77,31 @@ Array [ `; exports[`uses default memory buffer logger until config is provided 1`] = ` -Array [ - Array [ - Object { - "context": "test.context", - "level": LogLevel { - "id": "trace", - "value": 7, - }, - "message": "trace message", - "meta": undefined, - "timestamp": 2012-02-01T00:00:00.000Z, - }, - ], - Array [ - Object { - "context": "test.context2", - "level": LogLevel { - "id": "fatal", - "value": 2, - }, - "message": "fatal message", - "meta": Object { - "some": "value", - }, - "timestamp": 2012-02-01T00:00:00.000Z, - }, - ], -] +Object { + "context": "test.context", + "level": LogLevel { + "id": "trace", + "value": 7, + }, + "message": "trace message", + "meta": undefined, + "pid": Any, + "timestamp": 2012-02-01T00:00:00.000Z, +} +`; + +exports[`uses default memory buffer logger until config is provided 2`] = ` +Object { + "context": "test.context2", + "level": LogLevel { + "id": "fatal", + "value": 2, + }, + "message": "fatal message", + "meta": Object { + "some": "value", + }, + "pid": Any, + "timestamp": 2012-02-01T00:00:00.000Z, +} `; diff --git a/src/core/server/logging/appenders/buffer/buffer_appender.test.ts b/src/core/server/logging/appenders/buffer/buffer_appender.test.ts index 453a29271c582..49d70db8d5d43 100644 --- a/src/core/server/logging/appenders/buffer/buffer_appender.test.ts +++ b/src/core/server/logging/appenders/buffer/buffer_appender.test.ts @@ -34,12 +34,14 @@ test('`flush()` returns all appended records and cleans internal buffer.', () => level: LogLevel.All, message: 'message-1', timestamp: new Date(), + pid: 5355, }, { context: 'context-2', level: LogLevel.Trace, message: 'message-2', timestamp: new Date(), + pid: 5355, }, ]; @@ -64,6 +66,7 @@ test('`dispose()` flushes internal buffer.', async () => { level: LogLevel.All, message: 'message-1', timestamp: new Date(), + pid: 5355, }); await appender.dispose(); diff --git a/src/core/server/logging/appenders/console/console_appender.test.ts b/src/core/server/logging/appenders/console/console_appender.test.ts index 364f0be7fadc3..6e30df1cfb65c 100644 --- a/src/core/server/logging/appenders/console/console_appender.test.ts +++ b/src/core/server/logging/appenders/console/console_appender.test.ts @@ -59,12 +59,14 @@ test('`append()` correctly formats records and pushes them to console.', () => { level: LogLevel.All, message: 'message-1', timestamp: new Date(), + pid: 5355, }, { context: 'context-2', level: LogLevel.Trace, message: 'message-2', timestamp: new Date(), + pid: 5355, }, { context: 'context-3', @@ -72,6 +74,7 @@ test('`append()` correctly formats records and pushes them to console.', () => { level: LogLevel.Fatal, message: 'message-3', timestamp: new Date(), + pid: 5355, }, ]; diff --git a/src/core/server/logging/appenders/file/file_appender.test.ts b/src/core/server/logging/appenders/file/file_appender.test.ts index fccca629f7d60..0483a06b199b6 100644 --- a/src/core/server/logging/appenders/file/file_appender.test.ts +++ b/src/core/server/logging/appenders/file/file_appender.test.ts @@ -70,6 +70,7 @@ test('file stream is created only once and only after first `append()` is called level: LogLevel.All, message: 'message-1', timestamp: new Date(), + pid: 5355, }); expect(mockCreateWriteStream).toHaveBeenCalledTimes(1); @@ -84,6 +85,7 @@ test('file stream is created only once and only after first `append()` is called level: LogLevel.All, message: 'message-2', timestamp: new Date(), + pid: 5355, }); expect(mockCreateWriteStream).not.toHaveBeenCalled(); @@ -99,12 +101,14 @@ test('`append()` correctly formats records and pushes them to the file.', () => level: LogLevel.All, message: 'message-1', timestamp: new Date(), + pid: 5355, }, { context: 'context-2', level: LogLevel.Trace, message: 'message-2', timestamp: new Date(), + pid: 5355, }, { context: 'context-3', @@ -112,6 +116,7 @@ test('`append()` correctly formats records and pushes them to the file.', () => level: LogLevel.Fatal, message: 'message-3', timestamp: new Date(), + pid: 5355, }, ]; @@ -160,6 +165,7 @@ test('`dispose()` closes stream.', async () => { level: LogLevel.All, message: 'message-1', timestamp: new Date(), + pid: 5355, }); await appender.dispose(); diff --git a/src/core/server/logging/layouts/__snapshots__/json_layout.test.ts.snap b/src/core/server/logging/layouts/__snapshots__/json_layout.test.ts.snap index d95c3893aa3d8..21cf4302c49dc 100644 --- a/src/core/server/logging/layouts/__snapshots__/json_layout.test.ts.snap +++ b/src/core/server/logging/layouts/__snapshots__/json_layout.test.ts.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`\`format()\` correctly formats record. 1`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-1\\",\\"error\\":{\\"message\\":\\"Some error message\\",\\"name\\":\\"Some error name\\",\\"stack\\":\\"Some error stack\\"},\\"level\\":\\"FATAL\\",\\"message\\":\\"message-1\\"}"`; +exports[`\`format()\` correctly formats record. 1`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-1\\",\\"error\\":{\\"message\\":\\"Some error message\\",\\"name\\":\\"Some error name\\",\\"stack\\":\\"Some error stack\\"},\\"level\\":\\"FATAL\\",\\"message\\":\\"message-1\\",\\"pid\\":5355}"`; -exports[`\`format()\` correctly formats record. 2`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-2\\",\\"level\\":\\"ERROR\\",\\"message\\":\\"message-2\\"}"`; +exports[`\`format()\` correctly formats record. 2`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-2\\",\\"level\\":\\"ERROR\\",\\"message\\":\\"message-2\\",\\"pid\\":5355}"`; -exports[`\`format()\` correctly formats record. 3`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-3\\",\\"level\\":\\"WARN\\",\\"message\\":\\"message-3\\"}"`; +exports[`\`format()\` correctly formats record. 3`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-3\\",\\"level\\":\\"WARN\\",\\"message\\":\\"message-3\\",\\"pid\\":5355}"`; -exports[`\`format()\` correctly formats record. 4`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-4\\",\\"level\\":\\"DEBUG\\",\\"message\\":\\"message-4\\"}"`; +exports[`\`format()\` correctly formats record. 4`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-4\\",\\"level\\":\\"DEBUG\\",\\"message\\":\\"message-4\\",\\"pid\\":5355}"`; -exports[`\`format()\` correctly formats record. 5`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-5\\",\\"level\\":\\"INFO\\",\\"message\\":\\"message-5\\"}"`; +exports[`\`format()\` correctly formats record. 5`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-5\\",\\"level\\":\\"INFO\\",\\"message\\":\\"message-5\\",\\"pid\\":5355}"`; -exports[`\`format()\` correctly formats record. 6`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-6\\",\\"level\\":\\"TRACE\\",\\"message\\":\\"message-6\\"}"`; +exports[`\`format()\` correctly formats record. 6`] = `"{\\"@timestamp\\":\\"2012-02-01T00:00:00.000Z\\",\\"context\\":\\"context-6\\",\\"level\\":\\"TRACE\\",\\"message\\":\\"message-6\\",\\"pid\\":5355}"`; diff --git a/src/core/server/logging/layouts/__snapshots__/pattern_layout.test.ts.snap b/src/core/server/logging/layouts/__snapshots__/pattern_layout.test.ts.snap index b727fc3c478ff..9ff4f7445d043 100644 --- a/src/core/server/logging/layouts/__snapshots__/pattern_layout.test.ts.snap +++ b/src/core/server/logging/layouts/__snapshots__/pattern_layout.test.ts.snap @@ -35,3 +35,15 @@ exports[`\`format()\` correctly formats record with highlighting. 4`] = `"[2012- exports[`\`format()\` correctly formats record with highlighting. 5`] = `"[2012-02-01T00:00:00.000Z][INFO ][context-5] message-5"`; exports[`\`format()\` correctly formats record with highlighting. 6`] = `"[2012-02-01T00:00:00.000Z][TRACE][context-6] message-6"`; + +exports[`allows specifying the PID in custom pattern 1`] = `"5355-context-1-Some error stack"`; + +exports[`allows specifying the PID in custom pattern 2`] = `"5355-context-2-message-2"`; + +exports[`allows specifying the PID in custom pattern 3`] = `"5355-context-3-message-3"`; + +exports[`allows specifying the PID in custom pattern 4`] = `"5355-context-4-message-4"`; + +exports[`allows specifying the PID in custom pattern 5`] = `"5355-context-5-message-5"`; + +exports[`allows specifying the PID in custom pattern 6`] = `"5355-context-6-message-6"`; diff --git a/src/core/server/logging/layouts/json_layout.test.ts b/src/core/server/logging/layouts/json_layout.test.ts index 49b8ddef07a63..2e4c5af80dd2e 100644 --- a/src/core/server/logging/layouts/json_layout.test.ts +++ b/src/core/server/logging/layouts/json_layout.test.ts @@ -32,36 +32,42 @@ const records: LogRecord[] = [ level: LogLevel.Fatal, message: 'message-1', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-2', level: LogLevel.Error, message: 'message-2', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-3', level: LogLevel.Warn, message: 'message-3', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-4', level: LogLevel.Debug, message: 'message-4', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-5', level: LogLevel.Info, message: 'message-5', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-6', level: LogLevel.Trace, message: 'message-6', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, ]; diff --git a/src/core/server/logging/layouts/json_layout.ts b/src/core/server/logging/layouts/json_layout.ts index 1dcc3fc3ebcf6..8e90b2f7eb782 100644 --- a/src/core/server/logging/layouts/json_layout.ts +++ b/src/core/server/logging/layouts/json_layout.ts @@ -58,6 +58,7 @@ export class JsonLayout implements Layout { level: record.level.id.toUpperCase(), message: record.message, meta: record.meta, + pid: record.pid, }); } } diff --git a/src/core/server/logging/layouts/pattern_layout.test.ts b/src/core/server/logging/layouts/pattern_layout.test.ts index ae8b39b9cc99a..23656c5d20510 100644 --- a/src/core/server/logging/layouts/pattern_layout.test.ts +++ b/src/core/server/logging/layouts/pattern_layout.test.ts @@ -33,36 +33,42 @@ const records: LogRecord[] = [ level: LogLevel.Fatal, message: 'message-1', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-2', level: LogLevel.Error, message: 'message-2', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-3', level: LogLevel.Warn, message: 'message-3', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-4', level: LogLevel.Debug, message: 'message-4', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-5', level: LogLevel.Info, message: 'message-5', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, { context: 'context-6', level: LogLevel.Trace, message: 'message-6', timestamp: new Date(Date.UTC(2012, 1, 1)), + pid: 5355, }, ]; @@ -119,3 +125,11 @@ test('`format()` correctly formats record with highlighting.', () => { expect(layout.format(record)).toMatchSnapshot(); } }); + +test('allows specifying the PID in custom pattern', () => { + const layout = new PatternLayout('{pid}-{context}-{message}'); + + for (const record of records) { + expect(layout.format(record)).toMatchSnapshot(); + } +}); diff --git a/src/core/server/logging/layouts/pattern_layout.ts b/src/core/server/logging/layouts/pattern_layout.ts index 8be47dbcdd095..64424c02268ff 100644 --- a/src/core/server/logging/layouts/pattern_layout.ts +++ b/src/core/server/logging/layouts/pattern_layout.ts @@ -32,6 +32,7 @@ const Parameters = Object.freeze({ Level: '{level}', Message: '{message}', Timestamp: '{timestamp}', + Pid: '{pid}', }); /** @@ -39,7 +40,7 @@ const Parameters = Object.freeze({ * with the actual data. */ const PATTERN_REGEX = new RegExp( - `${Parameters.Timestamp}|${Parameters.Level}|${Parameters.Context}|${Parameters.Message}`, + `${Parameters.Timestamp}|${Parameters.Level}|${Parameters.Context}|${Parameters.Message}|${Parameters.Pid}`, 'gi' ); @@ -103,6 +104,7 @@ export class PatternLayout implements Layout { [Parameters.Level, record.level.id.toUpperCase().padEnd(5)], [Parameters.Context, record.context], [Parameters.Message, message], + [Parameters.Pid, String(record.pid)], ]); if (this.highlight) { diff --git a/src/core/server/logging/log_record.ts b/src/core/server/logging/log_record.ts index e7f93f7fc3e14..6286d751bf41f 100644 --- a/src/core/server/logging/log_record.ts +++ b/src/core/server/logging/log_record.ts @@ -30,4 +30,5 @@ export interface LogRecord { message: string; error?: Error; meta?: { [name: string]: any }; + pid: number; } diff --git a/src/core/server/logging/logger.test.ts b/src/core/server/logging/logger.test.ts index 026e24fc5df54..1cc00a254300b 100644 --- a/src/core/server/logging/logger.test.ts +++ b/src/core/server/logging/logger.test.ts @@ -53,6 +53,7 @@ test('`trace()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-1', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -66,6 +67,7 @@ test('`trace()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-2', meta: { trace: true }, timestamp, + pid: expect.any(Number), }); } }); @@ -81,6 +83,7 @@ test('`debug()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-1', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -94,6 +97,7 @@ test('`debug()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-2', meta: { debug: true }, timestamp, + pid: expect.any(Number), }); } }); @@ -109,6 +113,7 @@ test('`info()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-1', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -122,6 +127,7 @@ test('`info()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-2', meta: { info: true }, timestamp, + pid: expect.any(Number), }); } }); @@ -137,6 +143,7 @@ test('`warn()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-1', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -151,6 +158,7 @@ test('`warn()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-2', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -164,6 +172,7 @@ test('`warn()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-3', meta: { warn: true }, timestamp, + pid: expect.any(Number), }); } }); @@ -179,6 +188,7 @@ test('`error()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-1', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -193,6 +203,7 @@ test('`error()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-2', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -206,6 +217,7 @@ test('`error()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-3', meta: { error: true }, timestamp, + pid: expect.any(Number), }); } }); @@ -221,6 +233,7 @@ test('`fatal()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-1', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -235,6 +248,7 @@ test('`fatal()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-2', meta: undefined, timestamp, + pid: expect.any(Number), }); } @@ -248,6 +262,7 @@ test('`fatal()` correctly forms `LogRecord` and passes it to all appenders.', () message: 'message-3', meta: { fatal: true }, timestamp, + pid: expect.any(Number), }); } }); @@ -258,6 +273,7 @@ test('`log()` just passes the record to all appenders.', () => { level: LogLevel.Info, message: 'message-1', timestamp, + pid: 5355, }; logger.log(record); @@ -307,6 +323,7 @@ test('logger with `All` level passes all records to appenders.', () => { level: LogLevel.Trace, message: 'trace-message', timestamp, + pid: expect.any(Number), }); } @@ -318,6 +335,7 @@ test('logger with `All` level passes all records to appenders.', () => { level: LogLevel.Debug, message: 'debug-message', timestamp, + pid: expect.any(Number), }); } @@ -329,6 +347,7 @@ test('logger with `All` level passes all records to appenders.', () => { level: LogLevel.Info, message: 'info-message', timestamp, + pid: expect.any(Number), }); } @@ -340,6 +359,7 @@ test('logger with `All` level passes all records to appenders.', () => { level: LogLevel.Warn, message: 'warn-message', timestamp, + pid: expect.any(Number), }); } @@ -351,6 +371,7 @@ test('logger with `All` level passes all records to appenders.', () => { level: LogLevel.Error, message: 'error-message', timestamp, + pid: expect.any(Number), }); } @@ -362,6 +383,7 @@ test('logger with `All` level passes all records to appenders.', () => { level: LogLevel.Fatal, message: 'fatal-message', timestamp, + pid: expect.any(Number), }); } }); @@ -385,6 +407,7 @@ test('passes log record to appenders only if log level is supported.', () => { level: LogLevel.Warn, message: 'warn-message', timestamp, + pid: expect.any(Number), }); } @@ -396,6 +419,7 @@ test('passes log record to appenders only if log level is supported.', () => { level: LogLevel.Error, message: 'error-message', timestamp, + pid: expect.any(Number), }); } @@ -407,6 +431,7 @@ test('passes log record to appenders only if log level is supported.', () => { level: LogLevel.Fatal, message: 'fatal-message', timestamp, + pid: expect.any(Number), }); } }); diff --git a/src/core/server/logging/logger.ts b/src/core/server/logging/logger.ts index ac79c1916c07b..285998c23832c 100644 --- a/src/core/server/logging/logger.ts +++ b/src/core/server/logging/logger.ts @@ -162,6 +162,7 @@ export class BaseLogger implements Logger { message: errorOrMessage.message, meta, timestamp: new Date(), + pid: process.pid, }; } @@ -171,6 +172,7 @@ export class BaseLogger implements Logger { message: errorOrMessage, meta, timestamp: new Date(), + pid: process.pid, }; } } diff --git a/src/core/server/logging/logging_service.test.ts b/src/core/server/logging/logging_service.test.ts index c58103cca5f8d..51697fd15bebe 100644 --- a/src/core/server/logging/logging_service.test.ts +++ b/src/core/server/logging/logging_service.test.ts @@ -23,6 +23,8 @@ jest.mock('fs', () => ({ createWriteStream: jest.fn(() => ({ write: mockStreamWrite })), })); +const dynamicProps = { pid: expect.any(Number) }; + jest.mock('../../../legacy/server/logging/rotate', () => ({ setupLoggingRotate: jest.fn().mockImplementation(() => Promise.resolve({})), })); @@ -58,7 +60,9 @@ test('uses default memory buffer logger until config is provided', () => { const anotherLogger = service.get('test', 'context2'); anotherLogger.fatal('fatal message', { some: 'value' }); - expect(bufferAppendSpy.mock.calls).toMatchSnapshot(); + expect(bufferAppendSpy).toHaveBeenCalledTimes(2); + expect(bufferAppendSpy.mock.calls[0][0]).toMatchSnapshot(dynamicProps); + expect(bufferAppendSpy.mock.calls[1][0]).toMatchSnapshot(dynamicProps); }); test('flushes memory buffer logger and switches to real logger once config is provided', () => { @@ -78,12 +82,15 @@ test('flushes memory buffer logger and switches to real logger once config is pr }) ); - expect(mockConsoleLog.mock.calls).toMatchSnapshot('buffered messages'); + expect(JSON.parse(mockConsoleLog.mock.calls[0][0])).toMatchSnapshot( + dynamicProps, + 'buffered messages' + ); mockConsoleLog.mockClear(); // Now message should go straight to thew newly configured appender, not buffered one. logger.info('some new info message'); - expect(mockConsoleLog.mock.calls).toMatchSnapshot('new messages'); + expect(JSON.parse(mockConsoleLog.mock.calls[0][0])).toMatchSnapshot(dynamicProps, 'new messages'); expect(bufferAppendSpy).not.toHaveBeenCalled(); }); @@ -114,8 +121,12 @@ test('appends records via multiple appenders.', () => { ); // Now all logs should added to configured appenders. - expect(mockConsoleLog.mock.calls).toMatchSnapshot('console logs'); - expect(mockStreamWrite.mock.calls).toMatchSnapshot('file logs'); + expect(mockConsoleLog).toHaveBeenCalledTimes(1); + expect(mockConsoleLog.mock.calls[0][0]).toMatchSnapshot('console logs'); + + expect(mockStreamWrite).toHaveBeenCalledTimes(2); + expect(mockStreamWrite.mock.calls[0][0]).toMatchSnapshot('file logs'); + expect(mockStreamWrite.mock.calls[1][0]).toMatchSnapshot('file logs'); }); test('uses `root` logger if context is not specified.', () => { @@ -163,5 +174,9 @@ test('asLoggerFactory() only allows to create new loggers.', () => { logger.fatal('buffered fatal message'); expect(Object.keys(service.asLoggerFactory())).toEqual(['get']); - expect(mockConsoleLog.mock.calls).toMatchSnapshot(); + + expect(mockConsoleLog).toHaveBeenCalledTimes(3); + expect(JSON.parse(mockConsoleLog.mock.calls[0][0])).toMatchSnapshot(dynamicProps); + expect(JSON.parse(mockConsoleLog.mock.calls[1][0])).toMatchSnapshot(dynamicProps); + expect(JSON.parse(mockConsoleLog.mock.calls[2][0])).toMatchSnapshot(dynamicProps); }); diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts index 97f836f8ef37d..9a7868d568ea0 100644 --- a/src/core/server/mocks.ts +++ b/src/core/server/mocks.ts @@ -38,6 +38,7 @@ export { httpServiceMock } from './http/http_service.mock'; export { loggingServiceMock } from './logging/logging_service.mock'; export { savedObjectsClientMock } from './saved_objects/service/saved_objects_client.mock'; export { savedObjectsRepositoryMock } from './saved_objects/service/lib/repository.mock'; +export { typeRegistryMock as savedObjectsTypeRegistryMock } from './saved_objects/saved_objects_type_registry.mock'; export { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; import { uuidServiceMock } from './uuid/uuid_service.mock'; @@ -112,12 +113,19 @@ function createCoreSetupMock() { const uiSettingsMock = { register: uiSettingsServiceMock.createSetupContract().register, }; + + const savedObjectsService = savedObjectsServiceMock.createSetupContract(); + const savedObjectMock: jest.Mocked = { + addClientWrapper: savedObjectsService.addClientWrapper, + setClientFactoryProvider: savedObjectsService.setClientFactoryProvider, + }; + const mock: CoreSetupMockType = { capabilities: capabilitiesServiceMock.createSetupContract(), context: contextServiceMock.createSetupContract(), elasticsearch: elasticsearchServiceMock.createSetup(), http: httpMock, - savedObjects: savedObjectsServiceMock.createSetupContract(), + savedObjects: savedObjectMock, uiSettings: uiSettingsMock, uuid: uuidServiceMock.createSetupContract(), getStartServices: jest @@ -145,7 +153,7 @@ function createInternalCoreSetupMock() { elasticsearch: elasticsearchServiceMock.createInternalSetup(), http: httpServiceMock.createSetupContract(), uiSettings: uiSettingsServiceMock.createSetupContract(), - savedObjects: savedObjectsServiceMock.createSetupContract(), + savedObjects: savedObjectsServiceMock.createInternalSetupContract(), uuid: uuidServiceMock.createSetupContract(), }; return setupDeps; @@ -154,7 +162,7 @@ function createInternalCoreSetupMock() { function createInternalCoreStartMock() { const startDeps: InternalCoreStart = { capabilities: capabilitiesServiceMock.createStartContract(), - savedObjects: savedObjectsServiceMock.createStartContract(), + savedObjects: savedObjectsServiceMock.createInternalStartContract(), uiSettings: uiSettingsServiceMock.createStartContract(), }; return startDeps; diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index 77300900e84f3..a7b555a9eba01 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -205,6 +205,7 @@ export function createPluginStartContext( getScopedClient: deps.savedObjects.getScopedClient, createInternalRepository: deps.savedObjects.createInternalRepository, createScopedRepository: deps.savedObjects.createScopedRepository, + createSerializer: deps.savedObjects.createSerializer, }, uiSettings: { asScopedToClient: deps.uiSettings.asScopedToClient, diff --git a/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap b/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap new file mode 100644 index 0000000000000..7846e7f1a802a --- /dev/null +++ b/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap @@ -0,0 +1,144 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`convertLegacyTypes converts the legacy mappings using default values if no schemas are specified 1`] = ` +Array [ + Object { + "convertToAliasScript": undefined, + "hidden": false, + "indexPattern": undefined, + "mappings": Object { + "properties": Object { + "fieldA": Object { + "type": "text", + }, + }, + }, + "migrations": Object {}, + "name": "typeA", + "namespaceAgnostic": false, + }, + Object { + "convertToAliasScript": undefined, + "hidden": false, + "indexPattern": undefined, + "mappings": Object { + "properties": Object { + "fieldB": Object { + "type": "text", + }, + }, + }, + "migrations": Object {}, + "name": "typeB", + "namespaceAgnostic": false, + }, + Object { + "convertToAliasScript": undefined, + "hidden": false, + "indexPattern": undefined, + "mappings": Object { + "properties": Object { + "fieldC": Object { + "type": "text", + }, + }, + }, + "migrations": Object {}, + "name": "typeC", + "namespaceAgnostic": false, + }, +] +`; + +exports[`convertLegacyTypes merges everything when all are present 1`] = ` +Array [ + Object { + "convertToAliasScript": undefined, + "hidden": true, + "indexPattern": "myIndex", + "mappings": Object { + "properties": Object { + "fieldA": Object { + "type": "text", + }, + }, + }, + "migrations": Object { + "1.0.0": [MockFunction], + "2.0.4": [MockFunction], + }, + "name": "typeA", + "namespaceAgnostic": true, + }, + Object { + "convertToAliasScript": "some alias script", + "hidden": false, + "indexPattern": undefined, + "mappings": Object { + "properties": Object { + "anotherFieldB": Object { + "type": "boolean", + }, + "fieldB": Object { + "type": "text", + }, + }, + }, + "migrations": Object {}, + "name": "typeB", + "namespaceAgnostic": false, + }, + Object { + "convertToAliasScript": undefined, + "hidden": false, + "indexPattern": undefined, + "mappings": Object { + "properties": Object { + "fieldC": Object { + "type": "text", + }, + }, + }, + "migrations": Object { + "1.5.3": [MockFunction], + }, + "name": "typeC", + "namespaceAgnostic": false, + }, +] +`; + +exports[`convertLegacyTypes merges the mappings and the schema to create the type when schema exists for the type 1`] = ` +Array [ + Object { + "convertToAliasScript": undefined, + "hidden": true, + "indexPattern": "fooBar", + "mappings": Object { + "properties": Object { + "fieldA": Object { + "type": "text", + }, + }, + }, + "migrations": Object {}, + "name": "typeA", + "namespaceAgnostic": true, + }, + Object { + "convertToAliasScript": undefined, + "hidden": false, + "indexPattern": undefined, + "mappings": Object { + "properties": Object { + "fieldC": Object { + "type": "text", + }, + }, + }, + "migrations": Object {}, + "name": "typeC", + "namespaceAgnostic": false, + }, +] +`; diff --git a/src/core/server/saved_objects/index.ts b/src/core/server/saved_objects/index.ts index 181025d73817d..529ee9599f178 100644 --- a/src/core/server/saved_objects/index.ts +++ b/src/core/server/saved_objects/index.ts @@ -31,7 +31,12 @@ export { SavedObjectsExportResultDetails, } from './export'; -export { SavedObjectsSerializer, RawDoc as SavedObjectsRawDoc } from './serialization'; +export { + SavedObjectsSerializer, + SavedObjectsRawDoc, + SavedObjectSanitizedDoc, + SavedObjectUnsanitizedDoc, +} from './serialization'; export { SavedObjectsMigrationLogger } from './migrations/core/migration_logger'; @@ -50,4 +55,18 @@ export { SavedObjectsDeleteByNamespaceOptions, } from './service/lib/repository'; +export { + SavedObjectsCoreFieldMapping, + SavedObjectsComplexFieldMapping, + SavedObjectsFieldMapping, + SavedObjectsMappingProperties, + SavedObjectsTypeMappingDefinition, + SavedObjectsTypeMappingDefinitions, +} from './mappings'; + +export { SavedObjectMigrationMap, SavedObjectMigrationFn } from './migrations'; + +export { SavedObjectsType } from './types'; + export { config } from './saved_objects_config'; +export { SavedObjectTypeRegistry, ISavedObjectTypeRegistry } from './saved_objects_type_registry'; diff --git a/src/core/server/saved_objects/mappings/index.ts b/src/core/server/saved_objects/mappings/index.ts index 15b0736ca5f1f..e1d718ee454ce 100644 --- a/src/core/server/saved_objects/mappings/index.ts +++ b/src/core/server/saved_objects/mappings/index.ts @@ -18,9 +18,12 @@ */ export { getTypes, getProperty, getRootProperties, getRootPropertiesObjects } from './lib'; export { - FieldMapping, - MappingMeta, - MappingProperties, + SavedObjectsComplexFieldMapping, + SavedObjectsCoreFieldMapping, + SavedObjectsTypeMappingDefinition, + SavedObjectsTypeMappingDefinitions, + SavedObjectsMappingProperties, + SavedObjectsFieldMapping, + IndexMappingMeta, IndexMapping, - SavedObjectsMapping, } from './types'; diff --git a/src/core/server/saved_objects/mappings/lib/get_property.test.ts b/src/core/server/saved_objects/mappings/lib/get_property.test.ts index a85697ddd08b8..a271cf3826e5d 100644 --- a/src/core/server/saved_objects/mappings/lib/get_property.test.ts +++ b/src/core/server/saved_objects/mappings/lib/get_property.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { FieldMapping, IndexMapping } from '../types'; +import { SavedObjectsFieldMapping, IndexMapping } from '../types'; import { getProperty } from './get_property'; const MAPPINGS = { @@ -47,7 +47,7 @@ const MAPPINGS = { }, }; -function runTest(key: string | string[], mapping: IndexMapping | FieldMapping) { +function runTest(key: string | string[], mapping: IndexMapping | SavedObjectsFieldMapping) { expect(typeof key === 'string' || Array.isArray(key)).toBeTruthy(); expect(typeof mapping).toBe('object'); diff --git a/src/core/server/saved_objects/mappings/lib/get_property.ts b/src/core/server/saved_objects/mappings/lib/get_property.ts index 4e9ff10fc5d47..a31c9fe0c3ba1 100644 --- a/src/core/server/saved_objects/mappings/lib/get_property.ts +++ b/src/core/server/saved_objects/mappings/lib/get_property.ts @@ -18,15 +18,15 @@ */ import toPath from 'lodash/internal/toPath'; -import { CoreFieldMapping, FieldMapping, IndexMapping } from '../types'; +import { SavedObjectsCoreFieldMapping, SavedObjectsFieldMapping, IndexMapping } from '../types'; function getPropertyMappingFromObjectMapping( - mapping: IndexMapping | FieldMapping, + mapping: IndexMapping | SavedObjectsFieldMapping, path: string[] -): FieldMapping | undefined { +): SavedObjectsFieldMapping | undefined { const props = (mapping && (mapping as IndexMapping).properties) || - (mapping && (mapping as CoreFieldMapping).fields); + (mapping && (mapping as SavedObjectsCoreFieldMapping).fields); if (!props) { return undefined; @@ -39,6 +39,9 @@ function getPropertyMappingFromObjectMapping( } } -export function getProperty(mappings: IndexMapping | FieldMapping, path: string | string[]) { +export function getProperty( + mappings: IndexMapping | SavedObjectsFieldMapping, + path: string | string[] +) { return getPropertyMappingFromObjectMapping(mappings, toPath(path)); } diff --git a/src/core/server/saved_objects/mappings/lib/get_root_properties_objects.ts b/src/core/server/saved_objects/mappings/lib/get_root_properties_objects.ts index 61e4d752445c4..81ba1d8235561 100644 --- a/src/core/server/saved_objects/mappings/lib/get_root_properties_objects.ts +++ b/src/core/server/saved_objects/mappings/lib/get_root_properties_objects.ts @@ -17,7 +17,11 @@ * under the License. */ -import { ComplexFieldMapping, IndexMapping, MappingProperties } from '../types'; +import { + SavedObjectsComplexFieldMapping, + IndexMapping, + SavedObjectsMappingProperties, +} from '../types'; import { getRootProperties } from './get_root_properties'; /** @@ -43,10 +47,10 @@ export function getRootPropertiesObjects(mappings: IndexMapping) { // we consider the existence of the properties or type of object to designate that this is an object datatype if ( !blacklist.includes(key) && - ((value as ComplexFieldMapping).properties || value.type === 'object') + ((value as SavedObjectsComplexFieldMapping).properties || value.type === 'object') ) { acc[key] = value; } return acc; - }, {} as MappingProperties); + }, {} as SavedObjectsMappingProperties); } diff --git a/src/core/server/saved_objects/mappings/types.ts b/src/core/server/saved_objects/mappings/types.ts index 8bb1a69d2eb13..578fdcea3718e 100644 --- a/src/core/server/saved_objects/mappings/types.ts +++ b/src/core/server/saved_objects/mappings/types.ts @@ -17,47 +17,133 @@ * under the License. */ -// FieldMapping isn't 1:1 with the options available, -// modify as needed. -export interface CoreFieldMapping { - type: string; - fields?: { - [subfield: string]: { - type: string; - }; - }; +/** + * Describe a saved object type mapping. + * + * @example + * ```ts + * const typeDefinition: SavedObjectsTypeMappingDefinition = { + * properties: { + * enabled: { + * type: "boolean" + * }, + * sendUsageFrom: { + * ignore_above: 256, + * type: "keyword" + * }, + * lastReported: { + * type: "date" + * }, + * lastVersionChecked: { + * ignore_above: 256, + * type: "keyword" + * }, + * } + * } + * ``` + * + * @public + */ +export interface SavedObjectsTypeMappingDefinition { + properties: SavedObjectsMappingProperties; } -// FieldMapping isn't 1:1 with the options available, -// modify as needed. -export interface ComplexFieldMapping { - dynamic?: string; - type?: string; - properties: MappingProperties; -} +/** + * A map of {@link SavedObjectsTypeMappingDefinition | saved object type mappings} + * + * @example + * ```ts + * const mappings: SavedObjectsTypeMappingDefinitions = { + * someType: { + * properties: { + * enabled: { + * type: "boolean" + * }, + * field: { + * type: "keyword" + * }, + * }, + * }, + * anotherType: { + * properties: { + * enabled: { + * type: "boolean" + * }, + * lastReported: { + * type: "date" + * }, + * }, + * }, -export type FieldMapping = CoreFieldMapping | ComplexFieldMapping; + * } + * ``` + * @remark This is the format for the legacy `mappings.json` savedObject mapping file. + * + * @internal + */ +export interface SavedObjectsTypeMappingDefinitions { + [type: string]: SavedObjectsTypeMappingDefinition; +} -export interface MappingProperties { - [field: string]: FieldMapping; +/** + * Describe the fields of a {@link SavedObjectsTypeMappingDefinition | saved object type}. + * + * @public + */ +export interface SavedObjectsMappingProperties { + [field: string]: SavedObjectsFieldMapping; } -export interface SavedObjectsMapping { - pluginId: string; - properties: MappingProperties; +/** + * Describe a {@link SavedObjectsTypeMappingDefinition | saved object type mapping} field. + * + * Please refer to {@link https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html | elasticsearch documentation} + * For the mapping documentation + * + * @public + */ +export type SavedObjectsFieldMapping = + | SavedObjectsCoreFieldMapping + | SavedObjectsComplexFieldMapping; + +/** @internal */ +export interface IndexMapping { + dynamic?: string; + properties: SavedObjectsMappingProperties; + _meta?: IndexMappingMeta; } -export interface MappingMeta { +/** @internal */ +export interface IndexMappingMeta { // A dictionary of key -> md5 hash (e.g. 'dashboard': '24234qdfa3aefa3wa') // with each key being a root-level mapping property, and each value being // the md5 hash of that mapping's value when the index was created. migrationMappingPropertyHashes?: { [k: string]: string }; } -// IndexMapping isn't 1:1 with the options available, -// modify as needed. -export interface IndexMapping { +/** + * See {@link SavedObjectsFieldMapping} for documentation. + * + * @public + */ +export interface SavedObjectsCoreFieldMapping { + type: string; + index?: boolean; + enabled?: boolean; + fields?: { + [subfield: string]: { + type: string; + }; + }; +} + +/** + * See {@link SavedObjectsFieldMapping} for documentation. + * + * @public + */ +export interface SavedObjectsComplexFieldMapping { dynamic?: string; - properties: MappingProperties; - _meta?: MappingMeta; + type?: string; + properties: SavedObjectsMappingProperties; } diff --git a/src/core/server/saved_objects/migrations/core/build_active_mappings.test.ts b/src/core/server/saved_objects/migrations/core/build_active_mappings.test.ts index 71f589f24369a..821a10353f8ec 100644 --- a/src/core/server/saved_objects/migrations/core/build_active_mappings.test.ts +++ b/src/core/server/saved_objects/migrations/core/build_active_mappings.test.ts @@ -27,21 +27,19 @@ describe('buildActiveMappings', () => { bbb: { type: 'long' }, }; - expect(buildActiveMappings({ properties })).toMatchSnapshot(); + expect(buildActiveMappings(properties)).toMatchSnapshot(); }); test('disallows duplicate mappings', () => { const properties = { type: { type: 'long' } }; - expect(() => buildActiveMappings({ properties })).toThrow( - /Cannot redefine core mapping \"type\"/ - ); + expect(() => buildActiveMappings(properties)).toThrow(/Cannot redefine core mapping \"type\"/); }); test('disallows mappings with leading underscore', () => { const properties = { _hm: { type: 'keyword' } }; - expect(() => buildActiveMappings({ properties })).toThrow( + expect(() => buildActiveMappings(properties)).toThrow( /Invalid mapping \"_hm\"\. Mappings cannot start with _/ ); }); @@ -53,7 +51,7 @@ describe('buildActiveMappings', () => { ccc: { fields: { b: { type: 'text' }, a: { type: 'text' } }, type: 'keyword' }, }; - const mappings = buildActiveMappings({ properties }); + const mappings = buildActiveMappings(properties); const hashes = mappings._meta!.migrationMappingPropertyHashes!; expect(hashes.aaa).toBeDefined(); diff --git a/src/core/server/saved_objects/migrations/core/build_active_mappings.ts b/src/core/server/saved_objects/migrations/core/build_active_mappings.ts index 2cf640cceea83..3afe8aae119d9 100644 --- a/src/core/server/saved_objects/migrations/core/build_active_mappings.ts +++ b/src/core/server/saved_objects/migrations/core/build_active_mappings.ts @@ -22,31 +22,31 @@ */ import crypto from 'crypto'; -import _ from 'lodash'; -import { IndexMapping, MappingProperties } from './../../mappings'; +import { cloneDeep, mapValues } from 'lodash'; +import { + IndexMapping, + SavedObjectsMappingProperties, + SavedObjectsTypeMappingDefinitions, +} from './../../mappings'; /** * Creates an index mapping with the core properties required by saved object * indices, as well as the specified additional properties. * - * @param {Opts} opts - * @prop {MappingDefinition} properties - The mapping's properties - * @returns {IndexMapping} + * @param typeDefinitions - the type definitions to build mapping from. */ -export function buildActiveMappings({ - properties, -}: { - properties: MappingProperties; -}): IndexMapping { +export function buildActiveMappings( + typeDefinitions: SavedObjectsTypeMappingDefinitions | SavedObjectsMappingProperties +): IndexMapping { const mapping = defaultMapping(); - properties = validateAndMerge(mapping.properties, properties); + const mergedProperties = validateAndMerge(mapping.properties, typeDefinitions); - return _.cloneDeep({ + return cloneDeep({ ...mapping, - properties, + properties: mergedProperties, _meta: { - migrationMappingPropertyHashes: md5Values(properties), + migrationMappingPropertyHashes: md5Values(mergedProperties), }, }); } @@ -113,7 +113,7 @@ function canonicalStringify(obj: any): string { // Convert an object's values to md5 hash strings function md5Values(obj: any) { - return _.mapValues(obj, md5Object); + return mapValues(obj, md5Object); } // If something exists in actual, but is missing in expected, we don't @@ -171,12 +171,14 @@ function defaultMapping(): IndexMapping { }; } -function validateAndMerge(dest: MappingProperties, source: MappingProperties) { +function validateAndMerge( + dest: SavedObjectsMappingProperties, + source: SavedObjectsTypeMappingDefinitions | SavedObjectsMappingProperties +) { Object.keys(source).forEach(k => { if (k.startsWith('_')) { throw new Error(`Invalid mapping "${k}". Mappings cannot start with _.`); } - if (dest.hasOwnProperty(k)) { throw new Error(`Cannot redefine core mapping "${k}".`); } diff --git a/src/core/server/saved_objects/migrations/core/build_index_map.test.ts b/src/core/server/saved_objects/migrations/core/build_index_map.test.ts index bdc96323238c0..44add4e977006 100644 --- a/src/core/server/saved_objects/migrations/core/build_index_map.test.ts +++ b/src/core/server/saved_objects/migrations/core/build_index_map.test.ts @@ -18,20 +18,30 @@ */ import { createIndexMap } from './build_index_map'; -import { ObjectToConfigAdapter } from '../../../config'; -import { SavedObjectsSchema } from '../../schema'; -import { LegacyConfig } from '../../../legacy'; +import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; +import { SavedObjectsType } from '../../types'; -const config = (new ObjectToConfigAdapter({}) as unknown) as LegacyConfig; +const createRegistry = (...types: Array>) => { + const registry = new SavedObjectTypeRegistry(); + types.forEach(type => + registry.registerType({ + name: 'unknown', + namespaceAgnostic: false, + hidden: false, + mappings: { properties: {} }, + migrations: {}, + ...type, + }) + ); + return registry; +}; test('mappings without index pattern goes to default index', () => { const result = createIndexMap({ - config, kibanaIndexName: '.kibana', - schema: new SavedObjectsSchema({ - type1: { - isNamespaceAgnostic: false, - }, + registry: createRegistry({ + name: 'type1', + namespaceAgnostic: false, }), indexMap: { type1: { @@ -60,13 +70,11 @@ test('mappings without index pattern goes to default index', () => { test(`mappings with custom index pattern doesn't go to default index`, () => { const result = createIndexMap({ - config, kibanaIndexName: '.kibana', - schema: new SavedObjectsSchema({ - type1: { - isNamespaceAgnostic: false, - indexPattern: '.other_kibana', - }, + registry: createRegistry({ + name: 'type1', + namespaceAgnostic: false, + indexPattern: '.other_kibana', }), indexMap: { type1: { @@ -95,14 +103,12 @@ test(`mappings with custom index pattern doesn't go to default index`, () => { test('creating a script gets added to the index pattern', () => { const result = createIndexMap({ - config, kibanaIndexName: '.kibana', - schema: new SavedObjectsSchema({ - type1: { - isNamespaceAgnostic: false, - indexPattern: '.other_kibana', - convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`, - }, + registry: createRegistry({ + name: 'type1', + namespaceAgnostic: false, + indexPattern: '.other_kibana', + convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`, }), indexMap: { type1: { @@ -132,16 +138,19 @@ test('creating a script gets added to the index pattern', () => { test('throws when two scripts are defined for an index pattern', () => { const defaultIndex = '.kibana'; - const schema = new SavedObjectsSchema({ - type1: { - isNamespaceAgnostic: false, + const registry = createRegistry( + { + name: 'type1', + namespaceAgnostic: false, convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`, }, - type2: { - isNamespaceAgnostic: false, + { + name: 'type2', + namespaceAgnostic: false, convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`, - }, - }); + } + ); + const indexMap = { type1: { properties: { @@ -160,9 +169,8 @@ test('throws when two scripts are defined for an index pattern', () => { }; expect(() => createIndexMap({ - config, kibanaIndexName: defaultIndex, - schema, + registry, indexMap, }) ).toThrowErrorMatchingInlineSnapshot( diff --git a/src/core/server/saved_objects/migrations/core/build_index_map.ts b/src/core/server/saved_objects/migrations/core/build_index_map.ts index 914447563cc77..8f7fe2f8eac5b 100644 --- a/src/core/server/saved_objects/migrations/core/build_index_map.ts +++ b/src/core/server/saved_objects/migrations/core/build_index_map.ts @@ -17,39 +17,32 @@ * under the License. */ -import { MappingProperties } from '../../mappings'; -import { SavedObjectsSchema } from '../../schema'; -import { LegacyConfig } from '../../../legacy'; +import { SavedObjectsTypeMappingDefinitions } from '../../mappings'; +import { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; export interface CreateIndexMapOptions { - config: LegacyConfig; kibanaIndexName: string; - schema: SavedObjectsSchema; - indexMap: MappingProperties; + registry: ISavedObjectTypeRegistry; + indexMap: SavedObjectsTypeMappingDefinitions; } export interface IndexMap { [index: string]: { - typeMappings: MappingProperties; + typeMappings: SavedObjectsTypeMappingDefinitions; script?: string; }; } /* - * This file contains logic to convert savedObjectSchemas into a dictonary of indexes and documents + * This file contains logic to convert savedObjectSchemas into a dictionary of indexes and documents */ -export function createIndexMap({ - /** @deprecated Remove once savedObjectsSchemas are exposed from Core */ - config, - kibanaIndexName, - schema, - indexMap, -}: CreateIndexMapOptions) { +export function createIndexMap({ kibanaIndexName, registry, indexMap }: CreateIndexMapOptions) { const map: IndexMap = {}; Object.keys(indexMap).forEach(type => { - const script = schema.getConvertToAliasScript(type); + const typeDef = registry.getType(type); + const script = typeDef?.convertToAliasScript; // Defaults to kibanaIndexName if indexPattern isn't defined - const indexPattern = schema.getIndexForType(config, type) || kibanaIndexName; + const indexPattern = typeDef?.indexPattern || kibanaIndexName; if (!map.hasOwnProperty(indexPattern as string)) { map[indexPattern] = { typeMappings: {} }; } diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts index 38496a3503833..0e3a4780e12b6 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts @@ -18,41 +18,49 @@ */ import _ from 'lodash'; -import { RawSavedObjectDoc } from '../../serialization'; +import { SavedObjectUnsanitizedDoc } from '../../serialization'; import { DocumentMigrator } from './document_migrator'; import { loggingServiceMock } from '../../../logging/logging_service.mock'; +import { SavedObjectsType } from '../../types'; +import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; const mockLoggerFactory = loggingServiceMock.create(); const mockLogger = mockLoggerFactory.get('mock logger'); +const createRegistry = (...types: Array>) => { + const registry = new SavedObjectTypeRegistry(); + types.forEach(type => + registry.registerType({ + name: 'unknown', + namespaceAgnostic: false, + hidden: false, + mappings: { properties: {} }, + migrations: {}, + ...type, + }) + ); + return registry; +}; + describe('DocumentMigrator', () => { function testOpts() { return { kibanaVersion: '25.2.3', - migrations: {}, + typeRegistry: createRegistry(), validateDoc: _.noop, log: mockLogger, }; } - it('validates the migration definition', () => { - const invalidDefinition: any = { - kibanaVersion: '3.2.3', - migrations: 'hello', - validateDoc: _.noop, - }; - expect(() => new DocumentMigrator(invalidDefinition)).toThrow( - /Migration definition should be an object/i - ); - }); - it('validates individual migration definitions', () => { - const invalidDefinition: any = { + const invalidDefinition = { kibanaVersion: '3.2.3', - migrations: { - foo: _.noop, - }, + typeRegistry: createRegistry({ + name: 'foo', + migrations: _.noop as any, + }), validateDoc: _.noop, + log: mockLogger, }; expect(() => new DocumentMigrator(invalidDefinition)).toThrow( /Migration for type foo should be an object/i @@ -60,14 +68,16 @@ describe('DocumentMigrator', () => { }); it('validates individual migration semvers', () => { - const invalidDefinition: any = { + const invalidDefinition = { kibanaVersion: '3.2.3', - migrations: { - foo: { - bar: _.noop, + typeRegistry: createRegistry({ + name: 'foo', + migrations: { + bar: doc => doc, }, - }, + }), validateDoc: _.noop, + log: mockLogger, }; expect(() => new DocumentMigrator(invalidDefinition)).toThrow( /Expected all properties to be semvers/i @@ -75,14 +85,16 @@ describe('DocumentMigrator', () => { }); it('validates the migration function', () => { - const invalidDefinition: any = { + const invalidDefinition = { kibanaVersion: '3.2.3', - migrations: { - foo: { - '1.2.3': 23, + typeRegistry: createRegistry({ + name: 'foo', + migrations: { + '1.2.3': 23 as any, }, - }, + }), validateDoc: _.noop, + log: mockLogger, }; expect(() => new DocumentMigrator(invalidDefinition)).toThrow( /expected a function, but got 23/i @@ -92,11 +104,12 @@ describe('DocumentMigrator', () => { it('migrates type and attributes', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - user: { + typeRegistry: createRegistry({ + name: 'user', + migrations: { '1.2.3': setAttr('attributes.name', 'Chris'), }, - }, + }), }); const actual = migrator.migrate({ id: 'me', @@ -115,14 +128,15 @@ describe('DocumentMigrator', () => { it(`doesn't mutate the original document`, () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - user: { - '1.2.3': (doc: RawSavedObjectDoc) => { + typeRegistry: createRegistry({ + name: 'user', + migrations: { + '1.2.3': doc => { _.set(doc, 'attributes.name', 'Mike'); return doc; }, }, - }, + }), }); const originalDoc = { id: 'me', @@ -138,11 +152,12 @@ describe('DocumentMigrator', () => { it('migrates meta properties', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - acl: { + typeRegistry: createRegistry({ + name: 'acl', + migrations: { '2.3.5': setAttr('acl', 'admins-only,sucka!'), }, - }, + }), }); const actual = migrator.migrate({ id: 'me', @@ -163,11 +178,26 @@ describe('DocumentMigrator', () => { it('does not apply migrations to unrelated docs', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - aaa: { '1.0.0': setAttr('aaa', 'A') }, - bbb: { '1.0.0': setAttr('bbb', 'B') }, - ccc: { '1.0.0': setAttr('ccc', 'C') }, - }, + typeRegistry: createRegistry( + { + name: 'aaa', + migrations: { + '1.0.0': setAttr('aaa', 'A'), + }, + }, + { + name: 'bbb', + migrations: { + '1.0.0': setAttr('bbb', 'B'), + }, + }, + { + name: 'ccc', + migrations: { + '1.0.0': setAttr('ccc', 'C'), + }, + } + ), }); const actual = migrator.migrate({ id: 'me', @@ -185,11 +215,26 @@ describe('DocumentMigrator', () => { it('assumes documents w/ undefined migrationVersion are up to date', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - user: { '1.0.0': setAttr('aaa', 'A') }, - bbb: { '2.3.4': setAttr('bbb', 'B') }, - ccc: { '1.0.0': setAttr('ccc', 'C') }, - }, + typeRegistry: createRegistry( + { + name: 'user', + migrations: { + '1.0.0': setAttr('aaa', 'A'), + }, + }, + { + name: 'bbb', + migrations: { + '2.3.4': setAttr('bbb', 'B'), + }, + }, + { + name: 'ccc', + migrations: { + '1.0.0': setAttr('ccc', 'C'), + }, + } + ), }); const actual = migrator.migrate({ id: 'me', @@ -212,13 +257,14 @@ describe('DocumentMigrator', () => { it('only applies migrations that are more recent than the doc', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - dog: { + typeRegistry: createRegistry({ + name: 'dog', + migrations: { '1.2.3': setAttr('attributes.a', 'A'), '1.2.4': setAttr('attributes.b', 'B'), '2.0.1': setAttr('attributes.c', 'C'), }, - }, + }), }); const actual = migrator.migrate({ id: 'smelly', @@ -254,11 +300,12 @@ describe('DocumentMigrator', () => { it('rejects docs that belong to a newer plugin', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - dawg: { + typeRegistry: createRegistry({ + name: 'dawg', + migrations: { '1.2.3': setAttr('attributes.a', 'A'), }, - }, + }), }); expect(() => migrator.migrate({ @@ -276,13 +323,14 @@ describe('DocumentMigrator', () => { let count = 0; const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - dog: { + typeRegistry: createRegistry({ + name: 'dog', + migrations: { '2.2.4': setAttr('attributes.b', () => ++count), '10.0.1': setAttr('attributes.c', () => ++count), '1.2.3': setAttr('attributes.a', () => ++count), }, - }, + }), }); const actual = migrator.migrate({ id: 'smelly', @@ -301,14 +349,20 @@ describe('DocumentMigrator', () => { it('allows props to be added', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - animal: { - '1.0.0': setAttr('animal', (name: string) => `Animal: ${name}`), - }, - dog: { - '2.2.4': setAttr('animal', 'Doggie'), + typeRegistry: createRegistry( + { + name: 'animal', + migrations: { + '1.0.0': setAttr('animal', (name: string) => `Animal: ${name}`), + }, }, - }, + { + name: 'dog', + migrations: { + '2.2.4': setAttr('animal', 'Doggie'), + }, + } + ), }); const actual = migrator.migrate({ id: 'smelly', @@ -328,16 +382,22 @@ describe('DocumentMigrator', () => { it('allows props to be renamed', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - animal: { - '1.0.0': setAttr('animal', (name: string) => `Animal: ${name}`), - '3.2.1': renameAttr('animal', 'dawg'), - }, - dawg: { - '2.2.4': renameAttr('dawg', 'animal'), - '3.2.0': setAttr('dawg', (name: string) => `Dawg3.x: ${name}`), + typeRegistry: createRegistry( + { + name: 'animal', + migrations: { + '1.0.0': setAttr('animal', (name: string) => `Animal: ${name}`), + '3.2.1': renameAttr('animal', 'dawg'), + }, }, - }, + { + name: 'dawg', + migrations: { + '2.2.4': renameAttr('dawg', 'animal'), + '3.2.0': setAttr('dawg', (name: string) => `Dawg3.x: ${name}`), + }, + } + ), }); const actual = migrator.migrate({ id: 'smelly', @@ -358,14 +418,20 @@ describe('DocumentMigrator', () => { it('allows changing type', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - cat: { - '1.0.0': setAttr('attributes.name', (name: string) => `Kitty ${name}`), - }, - dog: { - '2.2.4': setAttr('type', 'cat'), + typeRegistry: createRegistry( + { + name: 'cat', + migrations: { + '1.0.0': setAttr('attributes.name', (name: string) => `Kitty ${name}`), + }, }, - }, + { + name: 'dog', + migrations: { + '2.2.4': setAttr('type', 'cat'), + }, + } + ), }); const actual = migrator.migrate({ id: 'smelly', @@ -384,11 +450,12 @@ describe('DocumentMigrator', () => { it('disallows updating a migrationVersion prop to a lower version', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - cat: { + typeRegistry: createRegistry({ + name: 'cat', + migrations: { '1.0.0': setAttr('migrationVersion.foo', '3.2.1'), }, - }, + }), }); expect(() => @@ -406,11 +473,12 @@ describe('DocumentMigrator', () => { it('disallows removing a migrationVersion prop', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - cat: { + typeRegistry: createRegistry({ + name: 'cat', + migrations: { '1.0.0': setAttr('migrationVersion', {}), }, - }, + }), }); expect(() => migrator.migrate({ @@ -427,8 +495,9 @@ describe('DocumentMigrator', () => { it('allows updating a migrationVersion prop to a later version', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - cat: { + typeRegistry: createRegistry({ + name: 'cat', + migrations: { '1.0.0': setAttr('migrationVersion.cat', '2.9.1'), '2.0.0': () => { throw new Error('POW!'); @@ -438,7 +507,7 @@ describe('DocumentMigrator', () => { }, '3.0.0': setAttr('attributes.name', 'Shiny'), }, - }, + }), }); const actual = migrator.migrate({ id: 'smelly', @@ -457,11 +526,12 @@ describe('DocumentMigrator', () => { it('allows adding props to migrationVersion', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - cat: { + typeRegistry: createRegistry({ + name: 'cat', + migrations: { '1.0.0': setAttr('migrationVersion.foo', '5.6.7'), }, - }, + }), }); const actual = migrator.migrate({ id: 'smelly', @@ -481,13 +551,14 @@ describe('DocumentMigrator', () => { const log = mockLogger; const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - dog: { + typeRegistry: createRegistry({ + name: 'dog', + migrations: { '1.2.3': () => { throw new Error('Dang diggity!'); }, }, - }, + }), log, }); const failedDoc = { @@ -511,15 +582,16 @@ describe('DocumentMigrator', () => { const logTestMsg = '...said the joker to the thief'; const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - dog: { + typeRegistry: createRegistry({ + name: 'dog', + migrations: { '1.2.3': (doc, log) => { log.info(logTestMsg); log.warning(logTestMsg); return doc; }, }, - }, + }), log: mockLogger, }); const doc = { @@ -536,17 +608,23 @@ describe('DocumentMigrator', () => { test('extracts the latest migration version info', () => { const { migrationVersion } = new DocumentMigrator({ ...testOpts(), - migrations: { - aaa: { - '1.2.3': (doc: RawSavedObjectDoc) => doc, - '10.4.0': (doc: RawSavedObjectDoc) => doc, - '2.2.1': (doc: RawSavedObjectDoc) => doc, - }, - bbb: { - '3.2.3': (doc: RawSavedObjectDoc) => doc, - '2.0.0': (doc: RawSavedObjectDoc) => doc, + typeRegistry: createRegistry( + { + name: 'aaa', + migrations: { + '1.2.3': (doc: SavedObjectUnsanitizedDoc) => doc, + '10.4.0': (doc: SavedObjectUnsanitizedDoc) => doc, + '2.2.1': (doc: SavedObjectUnsanitizedDoc) => doc, + }, }, - }, + { + name: 'bbb', + migrations: { + '3.2.3': (doc: SavedObjectUnsanitizedDoc) => doc, + '2.0.0': (doc: SavedObjectUnsanitizedDoc) => doc, + }, + } + ), }); expect(migrationVersion).toEqual({ @@ -558,11 +636,12 @@ describe('DocumentMigrator', () => { test('fails if the validate doc throws', () => { const migrator = new DocumentMigrator({ ...testOpts(), - migrations: { - aaa: { + typeRegistry: createRegistry({ + name: 'aaa', + migrations: { '2.3.4': d => _.set(d, 'attributes.counter', 42), }, - }, + }), validateDoc: d => { if ((d.attributes as any).counter === 42) { throw new Error('Meaningful!'); @@ -577,11 +656,15 @@ describe('DocumentMigrator', () => { }); function renameAttr(path: string, newPath: string) { - return (doc: RawSavedObjectDoc) => - _.omit(_.set(doc, newPath, _.get(doc, path)) as {}, path) as RawSavedObjectDoc; + return (doc: SavedObjectUnsanitizedDoc) => + _.omit(_.set(doc, newPath, _.get(doc, path)) as {}, path) as SavedObjectUnsanitizedDoc; } function setAttr(path: string, value: any) { - return (doc: RawSavedObjectDoc) => - _.set(doc, path, _.isFunction(value) ? value(_.get(doc, path)) : value) as RawSavedObjectDoc; + return (doc: SavedObjectUnsanitizedDoc) => + _.set( + doc, + path, + _.isFunction(value) ? value(_.get(doc, path)) : value + ) as SavedObjectUnsanitizedDoc; } diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.ts b/src/core/server/saved_objects/migrations/core/document_migrator.ts index 563d978dcc1f1..b5019b2874bec 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.ts @@ -65,23 +65,19 @@ import _ from 'lodash'; import cloneDeep from 'lodash.clonedeep'; import Semver from 'semver'; import { Logger } from '../../../logging'; -import { RawSavedObjectDoc } from '../../serialization'; +import { SavedObjectUnsanitizedDoc } from '../../serialization'; import { SavedObjectsMigrationVersion } from '../../types'; -import { MigrationLogger, SavedObjectsMigrationLogger } from './migration_logger'; +import { MigrationLogger } from './migration_logger'; +import { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; +import { SavedObjectMigrationFn } from '../types'; -export type TransformFn = (doc: RawSavedObjectDoc) => RawSavedObjectDoc; +export type TransformFn = (doc: SavedObjectUnsanitizedDoc) => SavedObjectUnsanitizedDoc; -type MigrationFn = (doc: RawSavedObjectDoc, log: SavedObjectsMigrationLogger) => RawSavedObjectDoc; +type ValidateDoc = (doc: SavedObjectUnsanitizedDoc) => void; -type ValidateDoc = (doc: RawSavedObjectDoc) => void; - -export interface MigrationDefinition { - [type: string]: { [version: string]: MigrationFn }; -} - -interface Opts { +interface DocumentMigratorOptions { kibanaVersion: string; - migrations: MigrationDefinition; + typeRegistry: ISavedObjectTypeRegistry; validateDoc: ValidateDoc; log: Logger; } @@ -114,22 +110,22 @@ export class DocumentMigrator implements VersionedTransformer { /** * Creates an instance of DocumentMigrator. * - * @param {Opts} opts + * @param {DocumentMigratorOptions} opts * @prop {string} kibanaVersion - The current version of Kibana - * @prop {MigrationDefinition} migrations - The migrations that will be used to migrate documents + * @prop {SavedObjectTypeRegistry} typeRegistry - The type registry to get type migrations from * @prop {ValidateDoc} validateDoc - A function which, given a document throws an error if it is * not up to date. This is used to ensure we don't let unmigrated documents slip through. * @prop {Logger} log - The migration logger * @memberof DocumentMigrator */ - constructor(opts: Opts) { - validateMigrationDefinition(opts.migrations); + constructor({ typeRegistry, kibanaVersion, log, validateDoc }: DocumentMigratorOptions) { + validateMigrationDefinition(typeRegistry); - this.migrations = buildActiveMigrations(opts.migrations, opts.log); + this.migrations = buildActiveMigrations(typeRegistry, log); this.transformDoc = buildDocumentTransform({ - kibanaVersion: opts.kibanaVersion, + kibanaVersion, migrations: this.migrations, - validateDoc: opts.validateDoc, + validateDoc, }); } @@ -147,11 +143,11 @@ export class DocumentMigrator implements VersionedTransformer { /** * Migrates a document to the latest version. * - * @param {RawSavedObjectDoc} doc - * @returns {RawSavedObjectDoc} + * @param {SavedObjectUnsanitizedDoc} doc + * @returns {SavedObjectUnsanitizedDoc} * @memberof DocumentMigrator */ - public migrate = (doc: RawSavedObjectDoc): RawSavedObjectDoc => { + public migrate = (doc: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc => { // Clone the document to prevent accidental mutations on the original data // Ex: Importing sample data that is cached at import level, migrations would // execute on mutated data the second time. @@ -166,7 +162,7 @@ export class DocumentMigrator implements VersionedTransformer { * language. So, this is just to provide a little developer-friendly error messaging. Joi was * giving weird errors, so we're just doing manual validation. */ -function validateMigrationDefinition(migrations: MigrationDefinition) { +function validateMigrationDefinition(registry: ISavedObjectTypeRegistry) { function assertObject(obj: any, prefix: string) { if (!obj || typeof obj !== 'object') { throw new Error(`${prefix} Got ${obj}.`); @@ -187,17 +183,17 @@ function validateMigrationDefinition(migrations: MigrationDefinition) { } } - assertObject(migrations, 'Migration definition should be an object.'); - - Object.entries(migrations).forEach(([type, versions]: any) => { - assertObject( - versions, - `Migration for type ${type} should be an object like { '2.0.0': (doc) => doc }.` - ); - Object.entries(versions).forEach(([version, fn]) => { - assertValidSemver(version, type); - assertValidTransform(fn, version, type); - }); + registry.getAllTypes().forEach(type => { + if (type.migrations) { + assertObject( + type.migrations, + `Migration for type ${type.name} should be an object like { '2.0.0': (doc) => doc }.` + ); + Object.entries(type.migrations).forEach(([version, fn]) => { + assertValidSemver(version, type.name); + assertValidTransform(fn, version, type.name); + }); + } }); } @@ -207,19 +203,28 @@ function validateMigrationDefinition(migrations: MigrationDefinition) { * From: { type: { version: fn } } * To: { type: { latestVersion: string, transforms: [{ version: string, transform: fn }] } } */ -function buildActiveMigrations(migrations: MigrationDefinition, log: Logger): ActiveMigrations { - return _.mapValues(migrations, (versions, prop) => { - const transforms = Object.entries(versions) - .map(([version, transform]) => ({ - version, - transform: wrapWithTry(version, prop!, transform, log), - })) - .sort((a, b) => Semver.compare(a.version, b.version)); - return { - latestVersion: _.last(transforms).version, - transforms, - }; - }); +function buildActiveMigrations( + typeRegistry: ISavedObjectTypeRegistry, + log: Logger +): ActiveMigrations { + return typeRegistry + .getAllTypes() + .filter(type => type.migrations && Object.keys(type.migrations).length > 0) + .reduce((migrations, type) => { + const transforms = Object.entries(type.migrations!) + .map(([version, transform]) => ({ + version, + transform: wrapWithTry(version, type.name, transform, log), + })) + .sort((a, b) => Semver.compare(a.version, b.version)); + return { + ...migrations, + [type.name]: { + latestVersion: _.last(transforms).version, + transforms, + }, + }; + }, {} as ActiveMigrations); } /** @@ -234,7 +239,7 @@ function buildDocumentTransform({ migrations: ActiveMigrations; validateDoc: ValidateDoc; }): TransformFn { - return function transformAndValidate(doc: RawSavedObjectDoc) { + return function transformAndValidate(doc: SavedObjectUnsanitizedDoc) { const result = doc.migrationVersion ? applyMigrations(doc, migrations) : markAsUpToDate(doc, migrations); @@ -252,7 +257,7 @@ function buildDocumentTransform({ }; } -function applyMigrations(doc: RawSavedObjectDoc, migrations: ActiveMigrations) { +function applyMigrations(doc: SavedObjectUnsanitizedDoc, migrations: ActiveMigrations) { while (true) { const prop = nextUnmigratedProp(doc, migrations); if (!prop) { @@ -265,14 +270,14 @@ function applyMigrations(doc: RawSavedObjectDoc, migrations: ActiveMigrations) { /** * Gets the doc's props, handling the special case of "type". */ -function props(doc: RawSavedObjectDoc) { +function props(doc: SavedObjectUnsanitizedDoc) { return Object.keys(doc).concat(doc.type); } /** * Looks up the prop version in a saved object document or in our latest migrations. */ -function propVersion(doc: RawSavedObjectDoc | ActiveMigrations, prop: string) { +function propVersion(doc: SavedObjectUnsanitizedDoc | ActiveMigrations, prop: string) { return ( (doc[prop] && doc[prop].latestVersion) || (doc.migrationVersion && (doc as any).migrationVersion[prop]) @@ -282,7 +287,7 @@ function propVersion(doc: RawSavedObjectDoc | ActiveMigrations, prop: string) { /** * Sets the doc's migrationVersion to be the most recent version */ -function markAsUpToDate(doc: RawSavedObjectDoc, migrations: ActiveMigrations) { +function markAsUpToDate(doc: SavedObjectUnsanitizedDoc, migrations: ActiveMigrations) { return { ...doc, migrationVersion: props(doc).reduce((acc, prop) => { @@ -296,20 +301,25 @@ function markAsUpToDate(doc: RawSavedObjectDoc, migrations: ActiveMigrations) { * If a specific transform function fails, this tacks on a bit of information * about the document and transform that caused the failure. */ -function wrapWithTry(version: string, prop: string, transform: MigrationFn, log: Logger) { - return function tryTransformDoc(doc: RawSavedObjectDoc) { +function wrapWithTry( + version: string, + type: string, + migrationFn: SavedObjectMigrationFn, + log: Logger +) { + return function tryTransformDoc(doc: SavedObjectUnsanitizedDoc) { try { - const result = transform(doc, new MigrationLogger(log)); + const result = migrationFn(doc, new MigrationLogger(log)); // A basic sanity check to help migration authors detect basic errors // (e.g. forgetting to return the transformed doc) if (!result || !result.type) { - throw new Error(`Invalid saved object returned from migration ${prop}:${version}.`); + throw new Error(`Invalid saved object returned from migration ${type}:${version}.`); } return result; } catch (error) { - const failedTransform = `${prop}:${version}`; + const failedTransform = `${type}:${version}`; const failedDoc = JSON.stringify(doc); log.warn( `Failed to transform document ${doc}. Transform: ${failedTransform}\nDoc: ${failedDoc}` @@ -322,7 +332,7 @@ function wrapWithTry(version: string, prop: string, transform: MigrationFn, log: /** * Finds the first unmigrated property in the specified document. */ -function nextUnmigratedProp(doc: RawSavedObjectDoc, migrations: ActiveMigrations) { +function nextUnmigratedProp(doc: SavedObjectUnsanitizedDoc, migrations: ActiveMigrations) { return props(doc).find(p => { const latestVersion = propVersion(migrations, p); const docVersion = propVersion(doc, p); @@ -352,10 +362,10 @@ function nextUnmigratedProp(doc: RawSavedObjectDoc, migrations: ActiveMigrations * Applies any relevent migrations to the document for the specified property. */ function migrateProp( - doc: RawSavedObjectDoc, + doc: SavedObjectUnsanitizedDoc, prop: string, migrations: ActiveMigrations -): RawSavedObjectDoc { +): SavedObjectUnsanitizedDoc { const originalType = doc.type; let migrationVersion = _.clone(doc.migrationVersion) || {}; const typeChanged = () => !doc.hasOwnProperty(prop) || doc.type !== originalType; @@ -376,7 +386,11 @@ function migrateProp( /** * Retrieves any prop transforms that have not been applied to doc. */ -function applicableTransforms(migrations: ActiveMigrations, doc: RawSavedObjectDoc, prop: string) { +function applicableTransforms( + migrations: ActiveMigrations, + doc: SavedObjectUnsanitizedDoc, + prop: string +) { const minVersion = propVersion(doc, prop); const { transforms } = migrations[prop]; return minVersion @@ -389,7 +403,7 @@ function applicableTransforms(migrations: ActiveMigrations, doc: RawSavedObjectD * has not mutated migrationVersion in an unsupported way. */ function updateMigrationVersion( - doc: RawSavedObjectDoc, + doc: SavedObjectUnsanitizedDoc, migrationVersion: SavedObjectsMigrationVersion, prop: string, version: string @@ -405,7 +419,7 @@ function updateMigrationVersion( * as this could get us into an infinite loop. So, we explicitly check for that here. */ function assertNoDowngrades( - doc: RawSavedObjectDoc, + doc: SavedObjectUnsanitizedDoc, migrationVersion: SavedObjectsMigrationVersion, prop: string, version: string diff --git a/src/core/server/saved_objects/migrations/core/index_migrator.test.ts b/src/core/server/saved_objects/migrations/core/index_migrator.test.ts index 2fc65f6e475d8..a9d0a339c229f 100644 --- a/src/core/server/saved_objects/migrations/core/index_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/core/index_migrator.test.ts @@ -18,8 +18,8 @@ */ import _ from 'lodash'; -import { SavedObjectsSchema } from '../../schema'; -import { RawSavedObjectDoc, SavedObjectsSerializer } from '../../serialization'; +import { SavedObjectUnsanitizedDoc, SavedObjectsSerializer } from '../../serialization'; +import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; import { IndexMigrator } from './index_migrator'; import { loggingServiceMock } from '../../../logging/logging_service.mock'; @@ -39,7 +39,7 @@ describe('IndexMigrator', () => { migrationVersion: {}, migrate: _.identity, }, - serializer: new SavedObjectsSerializer(new SavedObjectsSchema()), + serializer: new SavedObjectsSerializer(new SavedObjectTypeRegistry()), }; }); @@ -254,7 +254,7 @@ describe('IndexMigrator', () => { test('transforms all docs from the original index', async () => { let count = 0; const { callCluster } = testOpts; - const migrateDoc = jest.fn((doc: RawSavedObjectDoc) => { + const migrateDoc = jest.fn((doc: SavedObjectUnsanitizedDoc) => { return { ...doc, attributes: { name: ++count }, diff --git a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts index aa208a23954f0..89f3fde384848 100644 --- a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts +++ b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts @@ -18,17 +18,21 @@ */ import _ from 'lodash'; -import { SavedObjectsSchema } from '../../schema'; +import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; import { SavedObjectsSerializer } from '../../serialization'; import { migrateRawDocs } from './migrate_raw_docs'; describe('migrateRawDocs', () => { test('converts raw docs to saved objects', async () => { 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' } } }, - ]); + const result = migrateRawDocs( + new SavedObjectsSerializer(new SavedObjectTypeRegistry()), + transform, + [ + { _id: 'a:b', _source: { type: 'a', a: { name: 'AAA' } } }, + { _id: 'c:d', _source: { type: 'c', c: { name: 'DDD' } } }, + ] + ); expect(result).toEqual([ { @@ -48,10 +52,14 @@ describe('migrateRawDocs', () => { 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' } } }, - ]); + const result = migrateRawDocs( + new SavedObjectsSerializer(new SavedObjectTypeRegistry()), + transform, + [ + { _id: 'foo:b', _source: { type: 'a', a: { name: 'AAA' } } }, + { _id: 'c:d', _source: { type: 'c', c: { name: 'DDD' } } }, + ] + ); expect(result).toEqual([ { _id: 'foo:b', _source: { type: 'a', a: { name: 'AAA' } } }, diff --git a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts index c008b18619629..5fe15f40db8ec 100644 --- a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts +++ b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts @@ -21,7 +21,7 @@ * This file provides logic for migrating raw documents. */ -import { RawDoc, SavedObjectsSerializer } from '../../serialization'; +import { SavedObjectsRawDoc, SavedObjectsSerializer } from '../../serialization'; import { TransformFn } from './document_migrator'; /** @@ -29,14 +29,14 @@ import { TransformFn } from './document_migrator'; * of raw docs. Any raw docs that are not valid saved objects will simply be passed through. * * @param {TransformFn} migrateDoc - * @param {RawDoc[]} rawDocs - * @returns {RawDoc[]} + * @param {SavedObjectsRawDoc[]} rawDocs + * @returns {SavedObjectsRawDoc[]} */ export function migrateRawDocs( serializer: SavedObjectsSerializer, migrateDoc: TransformFn, - rawDocs: RawDoc[] -): RawDoc[] { + rawDocs: SavedObjectsRawDoc[] +): SavedObjectsRawDoc[] { return rawDocs.map(raw => { if (serializer.isRawSavedObject(raw)) { const savedObject = serializer.rawToSavedObject(raw); diff --git a/src/core/server/saved_objects/migrations/core/migration_context.ts b/src/core/server/saved_objects/migrations/core/migration_context.ts index d4e97ee6c5747..3a6145f5d9623 100644 --- a/src/core/server/saved_objects/migrations/core/migration_context.ts +++ b/src/core/server/saved_objects/migrations/core/migration_context.ts @@ -26,7 +26,7 @@ import { Logger } from 'src/core/server/logging'; import { SavedObjectsSerializer } from '../../serialization'; -import { MappingProperties } from '../../mappings'; +import { SavedObjectsTypeMappingDefinitions } from '../../mappings'; import { buildActiveMappings } from './build_active_mappings'; import { CallCluster } from './call_cluster'; import { VersionedTransformer } from './document_migrator'; @@ -40,7 +40,7 @@ export interface MigrationOpts { callCluster: CallCluster; index: string; log: Logger; - mappingProperties: MappingProperties; + mappingProperties: SavedObjectsTypeMappingDefinitions; documentMigrator: VersionedTransformer; serializer: SavedObjectsSerializer; convertToAliasScript?: string; @@ -107,9 +107,9 @@ function createSourceContext(source: FullIndexInfo, alias: string) { function createDestContext( source: FullIndexInfo, alias: string, - mappingProperties: MappingProperties + mappingProperties: SavedObjectsTypeMappingDefinitions ): FullIndexInfo { - const activeMappings = buildActiveMappings({ properties: mappingProperties }); + const activeMappings = buildActiveMappings(mappingProperties); return { aliases: {}, @@ -133,6 +133,5 @@ function createDestContext( function nextIndexName(indexName: string, alias: string) { const indexSuffix = (indexName.match(/[\d]+$/) || [])[0]; const indexNum = parseInt(indexSuffix, 10) || 0; - return `${alias}_${indexNum + 1}`; } diff --git a/src/core/server/saved_objects/migrations/core/migration_coordinator.test.ts b/src/core/server/saved_objects/migrations/core/migration_coordinator.test.ts index 818ca73b37189..800edaeaa5885 100644 --- a/src/core/server/saved_objects/migrations/core/migration_coordinator.test.ts +++ b/src/core/server/saved_objects/migrations/core/migration_coordinator.test.ts @@ -24,6 +24,7 @@ describe('coordinateMigration', () => { const log = { debug: jest.fn(), warning: jest.fn(), + warn: jest.fn(), info: jest.fn(), }; diff --git a/src/core/server/saved_objects/migrations/core/migration_logger.ts b/src/core/server/saved_objects/migrations/core/migration_logger.ts index 7c61d0c48d9bd..9dfb3abc8e72d 100644 --- a/src/core/server/saved_objects/migrations/core/migration_logger.ts +++ b/src/core/server/saved_objects/migrations/core/migration_logger.ts @@ -30,7 +30,11 @@ export type LogFn = (path: string[], message: string) => void; export interface SavedObjectsMigrationLogger { debug: (msg: string) => void; info: (msg: string) => void; + /** + * @deprecated Use `warn` instead. + */ warning: (msg: string) => void; + warn: (msg: string) => void; } export class MigrationLogger implements SavedObjectsMigrationLogger { @@ -43,4 +47,5 @@ export class MigrationLogger implements SavedObjectsMigrationLogger { public info = (msg: string) => this.logger.info(msg); public debug = (msg: string) => this.logger.debug(msg); public warning = (msg: string) => this.logger.warn(msg); + public warn = (msg: string) => this.logger.warn(msg); } diff --git a/src/core/server/saved_objects/migrations/index.ts b/src/core/server/saved_objects/migrations/index.ts index 6cb7ecac92ab9..e96986bd702e6 100644 --- a/src/core/server/saved_objects/migrations/index.ts +++ b/src/core/server/saved_objects/migrations/index.ts @@ -18,3 +18,4 @@ */ export { KibanaMigrator, IKibanaMigrator } from './kibana'; +export { SavedObjectMigrationFn, SavedObjectMigrationMap } from './types'; diff --git a/src/core/server/saved_objects/migrations/kibana/__snapshots__/kibana_migrator.test.ts.snap b/src/core/server/saved_objects/migrations/kibana/__snapshots__/kibana_migrator.test.ts.snap index 792b2063fc86d..37a73b11bbc48 100644 --- a/src/core/server/saved_objects/migrations/kibana/__snapshots__/kibana_migrator.test.ts.snap +++ b/src/core/server/saved_objects/migrations/kibana/__snapshots__/kibana_migrator.test.ts.snap @@ -4,8 +4,8 @@ exports[`KibanaMigrator getActiveMappings returns full index mappings w/ core pr Object { "_meta": Object { "migrationMappingPropertyHashes": Object { - "amap": "625b32086eb1d1203564cf85062dd22e", - "bmap": "625b32086eb1d1203564cf85062dd22e", + "amap": "510f1f0adb69830cf8a1c5ce2923ed82", + "bmap": "510f1f0adb69830cf8a1c5ce2923ed82", "config": "87aca8fdb053154f11383fce3dbf3edf", "migrationVersion": "4a1746014a75ade3a714e1db5763276f", "namespace": "2f4316de49999235636386fe51dc06c1", @@ -17,10 +17,18 @@ Object { "dynamic": "strict", "properties": Object { "amap": Object { - "type": "text", + "properties": Object { + "field": Object { + "type": "text", + }, + }, }, "bmap": Object { - "type": "text", + "properties": Object { + "field": Object { + "type": "text", + }, + }, }, "config": Object { "dynamic": "true", diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.mock.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.mock.ts index c1021018538d5..2ee656721abd0 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.mock.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.mock.ts @@ -19,28 +19,29 @@ import { KibanaMigrator } from './kibana_migrator'; import { buildActiveMappings } from '../core'; -import { SavedObjectsMapping } from '../../mappings'; -const { mergeProperties } = jest.requireActual('./kibana_migrator'); +const { mergeTypes } = jest.requireActual('./kibana_migrator'); +import { SavedObjectsType } from '../../types'; -const defaultSavedObjectMappings = [ +const defaultSavedObjectTypes: SavedObjectsType[] = [ { - pluginId: 'testplugin', - properties: { - testtype: { - properties: { - name: { type: 'keyword' }, - }, + name: 'testtype', + hidden: false, + namespaceAgnostic: false, + mappings: { + properties: { + name: { type: 'keyword' }, }, }, + migrations: {}, }, ]; const createMigrator = ( { - savedObjectMappings, + types, }: { - savedObjectMappings: SavedObjectsMapping[]; - } = { savedObjectMappings: defaultSavedObjectMappings } + types: SavedObjectsType[]; + } = { types: defaultSavedObjectTypes } ) => { const mockMigrator: jest.Mocked> = { runMigrations: jest.fn(), @@ -48,9 +49,7 @@ const createMigrator = ( migrateDocument: jest.fn(), }; - mockMigrator.getActiveMappings.mockReturnValue( - buildActiveMappings({ properties: mergeProperties(savedObjectMappings) }) - ); + mockMigrator.getActiveMappings.mockReturnValue(buildActiveMappings(mergeTypes(types))); mockMigrator.migrateDocument.mockImplementation(doc => doc); return mockMigrator; }; diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts index c6a72eb53d6c4..fd82bf282266e 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts @@ -17,45 +17,49 @@ * under the License. */ -import _ from 'lodash'; import { KibanaMigratorOptions, KibanaMigrator } from './kibana_migrator'; import { loggingServiceMock } from '../../../logging/logging_service.mock'; -import { SavedObjectsSchema } from '../../schema'; +import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; +import { SavedObjectsType } from '../../types'; + +const createRegistry = (types: Array>) => { + const registry = new SavedObjectTypeRegistry(); + types.forEach(type => + registry.registerType({ + name: 'unknown', + namespaceAgnostic: false, + hidden: false, + mappings: { properties: {} }, + migrations: {}, + ...type, + }) + ); + return registry; +}; describe('KibanaMigrator', () => { describe('getActiveMappings', () => { it('returns full index mappings w/ core properties', () => { const options = mockOptions(); - options.savedObjectMappings = [ + options.typeRegistry = createRegistry([ { - pluginId: 'aaa', - properties: { amap: { type: 'text' } }, + name: 'amap', + mappings: { + properties: { field: { type: 'text' } }, + }, }, { - pluginId: 'bbb', - properties: { bmap: { type: 'text' } }, + name: 'bmap', + indexPattern: 'other-index', + mappings: { + properties: { field: { type: 'text' } }, + }, }, - ]; + ]); + const mappings = new KibanaMigrator(options).getActiveMappings(); expect(mappings).toMatchSnapshot(); }); - - it('Fails if duplicate mappings are defined', () => { - const options = mockOptions(); - options.savedObjectMappings = [ - { - pluginId: 'aaa', - properties: { amap: { type: 'text' } }, - }, - { - pluginId: 'bbb', - properties: { amap: { type: 'long' } }, - }, - ]; - expect(() => new KibanaMigrator(options).getActiveMappings()).toThrow( - /Plugin bbb is attempting to redefine mapping "amap"/ - ); - }); }); describe('runMigrations', () => { @@ -78,41 +82,37 @@ describe('KibanaMigrator', () => { }); }); -function mockOptions({ configValues }: { configValues?: any } = {}): KibanaMigratorOptions { +function mockOptions(): KibanaMigratorOptions { const callCluster = jest.fn(); return { logger: loggingServiceMock.create().get(), kibanaVersion: '8.2.3', savedObjectValidations: {}, - savedObjectMigrations: {}, - savedObjectMappings: [ + typeRegistry: createRegistry([ { - pluginId: 'testtype', - properties: { - testtype: { - properties: { - name: { type: 'keyword' }, - }, + name: 'testtype', + hidden: false, + namespaceAgnostic: false, + mappings: { + properties: { + name: { type: 'keyword' }, }, }, + migrations: {}, }, { - pluginId: 'testtype2', - properties: { - testtype2: { - properties: { - name: { type: 'keyword' }, - }, + name: 'testtype2', + hidden: false, + namespaceAgnostic: false, + indexPattern: 'other-index', + mappings: { + properties: { + name: { type: 'keyword' }, }, }, + migrations: {}, }, - ], - savedObjectSchemas: new SavedObjectsSchema({ - testtype2: { - isNamespaceAgnostic: false, - indexPattern: 'other-index', - }, - }), + ]), kibanaConfig: { enabled: true, index: '.my-index', @@ -123,15 +123,6 @@ function mockOptions({ configValues }: { configValues?: any } = {}): KibanaMigra scrollDuration: '10m', skip: false, }, - config: { - get: (name: string) => { - if (configValues && configValues[name]) { - return configValues[name]; - } else { - throw new Error(`Unexpected config ${name}`); - } - }, - } as KibanaMigratorOptions['config'], callCluster, }; } diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts index 747b48a540109..9b4fe10a35100 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts @@ -24,30 +24,23 @@ import { Logger } from 'src/core/server/logging'; import { KibanaConfigType } from 'src/core/server/kibana_config'; -import { MappingProperties, SavedObjectsMapping, IndexMapping } from '../../mappings'; -import { SavedObjectsSchema } from '../../schema'; -import { RawSavedObjectDoc, SavedObjectsSerializer } from '../../serialization'; +import { IndexMapping, SavedObjectsTypeMappingDefinitions } from '../../mappings'; +import { SavedObjectUnsanitizedDoc, SavedObjectsSerializer } from '../../serialization'; import { docValidator, PropertyValidators } from '../../validation'; import { buildActiveMappings, CallCluster, IndexMigrator } from '../core'; -import { - DocumentMigrator, - VersionedTransformer, - MigrationDefinition, -} from '../core/document_migrator'; +import { DocumentMigrator, VersionedTransformer } from '../core/document_migrator'; import { createIndexMap } from '../core/build_index_map'; import { SavedObjectsConfigType } from '../../saved_objects_config'; -import { LegacyConfig } from '../../../legacy'; +import { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; +import { SavedObjectsType } from '../../types'; export interface KibanaMigratorOptions { callCluster: CallCluster; - config: LegacyConfig; + typeRegistry: ISavedObjectTypeRegistry; savedObjectsConfig: SavedObjectsConfigType; kibanaConfig: KibanaConfigType; kibanaVersion: string; logger: Logger; - savedObjectMappings: SavedObjectsMapping[]; - savedObjectMigrations: MigrationDefinition; - savedObjectSchemas: SavedObjectsSchema; savedObjectValidations: PropertyValidators; } @@ -58,13 +51,12 @@ export type IKibanaMigrator = Pick; */ export class KibanaMigrator { private readonly callCluster: CallCluster; - private readonly config: LegacyConfig; private readonly savedObjectsConfig: SavedObjectsConfigType; private readonly documentMigrator: VersionedTransformer; private readonly kibanaConfig: KibanaConfigType; private readonly log: Logger; - private readonly mappingProperties: MappingProperties; - private readonly schema: SavedObjectsSchema; + private readonly mappingProperties: SavedObjectsTypeMappingDefinitions; + private readonly typeRegistry: ISavedObjectTypeRegistry; private readonly serializer: SavedObjectsSerializer; private migrationResult?: Promise>; @@ -73,27 +65,23 @@ export class KibanaMigrator { */ constructor({ callCluster, - config, + typeRegistry, kibanaConfig, savedObjectsConfig, + savedObjectValidations, kibanaVersion, logger, - savedObjectMappings, - savedObjectMigrations, - savedObjectSchemas, - savedObjectValidations, }: KibanaMigratorOptions) { - this.config = config; this.callCluster = callCluster; this.kibanaConfig = kibanaConfig; this.savedObjectsConfig = savedObjectsConfig; - this.schema = savedObjectSchemas; - this.serializer = new SavedObjectsSerializer(this.schema); - this.mappingProperties = mergeProperties(savedObjectMappings || []); + this.typeRegistry = typeRegistry; + this.serializer = new SavedObjectsSerializer(this.typeRegistry); + this.mappingProperties = mergeTypes(this.typeRegistry.getAllTypes()); this.log = logger; this.documentMigrator = new DocumentMigrator({ kibanaVersion, - migrations: savedObjectMigrations || {}, + typeRegistry, validateDoc: docValidator(savedObjectValidations || {}), log: this.log, }); @@ -118,10 +106,9 @@ export class KibanaMigrator { private runMigrationsInternal() { const kibanaIndexName = this.kibanaConfig.index; const indexMap = createIndexMap({ - config: this.config, kibanaIndexName, indexMap: this.mappingProperties, - schema: this.schema, + registry: this.typeRegistry, }); const migrators = Object.keys(indexMap).map(index => { @@ -150,7 +137,7 @@ export class KibanaMigrator { * */ public getActiveMappings(): IndexMapping { - return buildActiveMappings({ properties: this.mappingProperties }); + return buildActiveMappings(this.mappingProperties); } /** @@ -159,7 +146,7 @@ export class KibanaMigrator { * @param doc - The saved object to migrate * @returns `doc` with all registered migrations applied. */ - public migrateDocument(doc: RawSavedObjectDoc): RawSavedObjectDoc { + public migrateDocument(doc: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc { return this.documentMigrator.migrate(doc); } } @@ -168,12 +155,15 @@ export class KibanaMigrator { * Merges savedObjectMappings properties into a single object, verifying that * no mappings are redefined. */ -export function mergeProperties(mappings: SavedObjectsMapping[]): MappingProperties { - return mappings.reduce((acc, { pluginId, properties }) => { - const duplicate = Object.keys(properties).find(k => acc.hasOwnProperty(k)); +export function mergeTypes(types: SavedObjectsType[]): SavedObjectsTypeMappingDefinitions { + return types.reduce((acc, { name: type, mappings }) => { + const duplicate = acc.hasOwnProperty(type); if (duplicate) { - throw new Error(`Plugin ${pluginId} is attempting to redefine mapping "${duplicate}".`); + throw new Error(`Type ${type} is already defined.`); } - return Object.assign(acc, properties); + return { + ...acc, + [type]: mappings, + }; }, {}); } diff --git a/src/core/server/saved_objects/migrations/types.ts b/src/core/server/saved_objects/migrations/types.ts new file mode 100644 index 0000000000000..01741dd2ded1a --- /dev/null +++ b/src/core/server/saved_objects/migrations/types.ts @@ -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. + */ + +import { SavedObjectUnsanitizedDoc } from '../serialization'; +import { SavedObjectsMigrationLogger } from './core/migration_logger'; + +/** + * A migration function defined for a {@link SavedObjectsType | saved objects type} + * used to migrate it's {@link SavedObjectUnsanitizedDoc | documents} + */ +export type SavedObjectMigrationFn = ( + doc: SavedObjectUnsanitizedDoc, + log: SavedObjectsMigrationLogger +) => SavedObjectUnsanitizedDoc; + +/** + * A map of {@link SavedObjectMigrationFn | migration functions} to be used for a given type. + * The map's keys must be valid semver versions. + * + * For a given document, only migrations with a higher version number than that of the document will be applied. + * Migrations are executed in order, starting from the lowest version and ending with the highest one. + * + * @example + * ```typescript + * const migrations: SavedObjectMigrationMap = { + * '1.0.0': migrateToV1, + * '2.1.0': migrateToV21 + * } + * ``` + * + * @public + */ +export interface SavedObjectMigrationMap { + [version: string]: SavedObjectMigrationFn; +} diff --git a/src/core/server/saved_objects/saved_objects_service.mock.ts b/src/core/server/saved_objects/saved_objects_service.mock.ts index a15d1f5b864b7..70f3d5a5b18e4 100644 --- a/src/core/server/saved_objects/saved_objects_service.mock.ts +++ b/src/core/server/saved_objects/saved_objects_service.mock.ts @@ -21,38 +21,60 @@ import { SavedObjectsService, InternalSavedObjectsServiceSetup, InternalSavedObjectsServiceStart, + SavedObjectsServiceSetup, + SavedObjectsServiceStart, } from './saved_objects_service'; import { mockKibanaMigrator } from './migrations/kibana/kibana_migrator.mock'; import { savedObjectsClientProviderMock } from './service/lib/scoped_client_provider.mock'; import { savedObjectsRepositoryMock } from './service/lib/repository.mock'; import { savedObjectsClientMock } from './service/saved_objects_client.mock'; +import { typeRegistryMock } from './saved_objects_type_registry.mock'; type SavedObjectsServiceContract = PublicMethodsOf; const createStartContractMock = () => { - const startContract: jest.Mocked = { - clientProvider: savedObjectsClientProviderMock.create(), + const startContrat: jest.Mocked = { getScopedClient: jest.fn(), createInternalRepository: jest.fn(), createScopedRepository: jest.fn(), - migrator: mockKibanaMigrator.create(), + createSerializer: jest.fn(), }; - startContract.getScopedClient.mockReturnValue(savedObjectsClientMock.create()); - startContract.createInternalRepository.mockReturnValue(savedObjectsRepositoryMock.create()); - startContract.createScopedRepository.mockReturnValue(savedObjectsRepositoryMock.create()); + startContrat.getScopedClient.mockReturnValue(savedObjectsClientMock.create()); + startContrat.createInternalRepository.mockReturnValue(savedObjectsRepositoryMock.create()); + startContrat.createScopedRepository.mockReturnValue(savedObjectsRepositoryMock.create()); + + return startContrat; +}; + +const createInternalStartContractMock = () => { + const internalStartContract: jest.Mocked = { + ...createStartContractMock(), + clientProvider: savedObjectsClientProviderMock.create(), + migrator: mockKibanaMigrator.create(), + typeRegistry: typeRegistryMock.create(), + }; - return startContract; + return internalStartContract; }; const createSetupContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = { setClientFactoryProvider: jest.fn(), addClientWrapper: jest.fn(), }; + return setupContract; }; +const createInternalSetupContractMock = () => { + const internalSetupContract: jest.Mocked = { + ...createSetupContractMock(), + registerType: jest.fn(), + }; + return internalSetupContract; +}; + const createSavedObjectsServiceMock = () => { const mocked: jest.Mocked = { setup: jest.fn(), @@ -60,14 +82,16 @@ const createSavedObjectsServiceMock = () => { stop: jest.fn(), }; - mocked.setup.mockResolvedValue(createSetupContractMock()); - mocked.start.mockResolvedValue(createStartContractMock()); + mocked.setup.mockResolvedValue(createInternalSetupContractMock()); + mocked.start.mockResolvedValue(createInternalStartContractMock()); mocked.stop.mockResolvedValue(); return mocked; }; export const savedObjectsServiceMock = { create: createSavedObjectsServiceMock, + createInternalSetupContract: createInternalSetupContractMock, createSetupContract: createSetupContractMock, + createInternalStartContract: createInternalStartContractMock, createStartContract: createStartContractMock, }; diff --git a/src/core/server/saved_objects/saved_objects_service.test.mocks.ts b/src/core/server/saved_objects/saved_objects_service.test.mocks.ts index a9ad0778d4757..8c1cd3411203a 100644 --- a/src/core/server/saved_objects/saved_objects_service.test.mocks.ts +++ b/src/core/server/saved_objects/saved_objects_service.test.mocks.ts @@ -19,6 +19,7 @@ import { mockKibanaMigrator } from './migrations/kibana/kibana_migrator.mock'; import { savedObjectsClientProviderMock } from './service/lib/scoped_client_provider.mock'; +import { typeRegistryMock } from './saved_objects_type_registry.mock'; export const migratorInstanceMock = mockKibanaMigrator.create(); export const KibanaMigratorMock = jest.fn().mockImplementation(() => migratorInstanceMock); @@ -30,3 +31,8 @@ export const clientProviderInstanceMock = savedObjectsClientProviderMock.create( jest.doMock('./service/lib/scoped_client_provider', () => ({ SavedObjectsClientProvider: jest.fn().mockImplementation(() => clientProviderInstanceMock), })); + +export const typeRegistryInstanceMock = typeRegistryMock.create(); +jest.doMock('./saved_objects_type_registry', () => ({ + SavedObjectTypeRegistry: jest.fn().mockImplementation(() => typeRegistryInstanceMock), +})); diff --git a/src/core/server/saved_objects/saved_objects_service.test.ts b/src/core/server/saved_objects/saved_objects_service.test.ts index 19798aa68928d..07e7d8db8b25c 100644 --- a/src/core/server/saved_objects/saved_objects_service.test.ts +++ b/src/core/server/saved_objects/saved_objects_service.test.ts @@ -21,6 +21,7 @@ import { KibanaMigratorMock, migratorInstanceMock, clientProviderInstanceMock, + typeRegistryInstanceMock, } from './saved_objects_service.test.mocks'; import { SavedObjectsService } from './saved_objects_service'; @@ -108,6 +109,25 @@ describe('SavedObjectsService', () => { ); }); }); + + describe('registerType', () => { + it('registers the type to the internal typeRegistry', async () => { + const coreContext = mockCoreContext.create(); + const soService = new SavedObjectsService(coreContext); + const setup = await soService.setup(createSetupDeps()); + + const type = { + name: 'someType', + hidden: false, + namespaceAgnostic: false, + mappings: { properties: {} }, + }; + setup.registerType(type); + + expect(typeRegistryInstanceMock.registerType).toHaveBeenCalledTimes(1); + expect(typeRegistryInstanceMock.registerType).toHaveBeenCalledWith(type); + }); + }); }); describe('#start()', () => { diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts index 0c985c71c7e2f..2f07dbe51a09e 100644 --- a/src/core/server/saved_objects/saved_objects_service.ts +++ b/src/core/server/saved_objects/saved_objects_service.ts @@ -21,7 +21,6 @@ import { CoreService } from 'src/core/types'; import { first, filter, take } from 'rxjs/operators'; import { SavedObjectsClient, - SavedObjectsSchema, SavedObjectsClientProvider, ISavedObjectsClientProvider, SavedObjectsClientProviderOptions, @@ -34,17 +33,17 @@ import { KibanaConfigType } from '../kibana_config'; import { migrationsRetryCallCluster } from '../elasticsearch/retry_call_cluster'; import { SavedObjectsConfigType } from './saved_objects_config'; import { KibanaRequest } from '../http'; -import { SavedObjectsClientContract } from './types'; +import { SavedObjectsClientContract, SavedObjectsType } from './types'; import { ISavedObjectsRepository, SavedObjectsRepository } from './service/lib/repository'; import { SavedObjectsClientFactoryProvider, SavedObjectsClientWrapperFactory, } from './service/lib/scoped_client_provider'; import { Logger } from '../logging'; -import { SavedObjectsMapping } from './mappings'; -import { MigrationDefinition } from './migrations/core/document_migrator'; -import { SavedObjectsSchemaDefinition } from './schema'; +import { convertLegacyTypes } from './utils'; +import { SavedObjectTypeRegistry, ISavedObjectTypeRegistry } from './saved_objects_type_registry'; import { PropertyValidators } from './validation'; +import { SavedObjectsSerializer } from './serialization'; /** * Saved Objects is Kibana's data persistence mechanism allowing plugins to @@ -70,6 +69,7 @@ import { PropertyValidators } from './validation'; * constructor. * * @example + * ```ts * import { SavedObjectsClient, CoreSetup } from 'src/core/server'; * * export class Plugin() { @@ -79,6 +79,7 @@ import { PropertyValidators } from './validation'; * }) * } * } + * ``` * * @public */ @@ -102,7 +103,9 @@ export interface SavedObjectsServiceSetup { /** * @internal */ -export type InternalSavedObjectsServiceSetup = SavedObjectsServiceSetup; +export interface InternalSavedObjectsServiceSetup extends SavedObjectsServiceSetup { + registerType: (type: SavedObjectsType) => void; +} /** * Saved Objects is Kibana's data persisentence mechanism allowing plugins to @@ -146,6 +149,10 @@ export interface SavedObjectsServiceStart { * @param extraTypes - A list of additional hidden types the repository should have access to. */ createInternalRepository: (extraTypes?: string[]) => ISavedObjectsRepository; + /** + * Creates a {@link SavedObjectsSerializer | serializer} that is aware of all registered types. + */ + createSerializer: () => SavedObjectsSerializer; } export interface InternalSavedObjectsServiceStart extends SavedObjectsServiceStart { @@ -157,6 +164,10 @@ export interface InternalSavedObjectsServiceStart extends SavedObjectsServiceSta * @deprecated Exposed only for injecting into Legacy */ clientProvider: ISavedObjectsClientProvider; + /** + * @deprecated Exposed only for injecting into Legacy + */ + typeRegistry: ISavedObjectTypeRegistry; } /** @@ -207,9 +218,7 @@ export class SavedObjectsService private clientFactoryProvider?: SavedObjectsClientFactoryProvider; private clientFactoryWrappers: WrappedClientFactoryWrapper[] = []; - private mappings: SavedObjectsMapping[] = []; - private migrations: MigrationDefinition = {}; - private schemas: SavedObjectsSchemaDefinition = {}; + private typeRegistry = new SavedObjectTypeRegistry(); private validations: PropertyValidators = {}; constructor(private readonly coreContext: CoreContext) { @@ -221,16 +230,12 @@ export class SavedObjectsService this.setupDeps = setupDeps; - const { - savedObjectSchemas: savedObjectsSchemasDefinition, - savedObjectMappings, - savedObjectMigrations, - savedObjectValidations, - } = setupDeps.legacyPlugins.uiExports; - this.mappings = savedObjectMappings; - this.migrations = savedObjectMigrations; - this.schemas = savedObjectsSchemasDefinition; - this.validations = savedObjectValidations; + const legacyTypes = convertLegacyTypes( + setupDeps.legacyPlugins.uiExports, + setupDeps.legacyPlugins.pluginExtendedConfig + ); + legacyTypes.forEach(type => this.typeRegistry.registerType(type)); + this.validations = setupDeps.legacyPlugins.uiExports.savedObjectValidations || {}; return { setClientFactoryProvider: provider => { @@ -246,6 +251,9 @@ export class SavedObjectsService factory, }); }, + registerType: type => { + this.typeRegistry.registerType(type); + }, }; } @@ -303,8 +311,7 @@ export class SavedObjectsService const createRepository = (callCluster: APICaller, extraTypes: string[] = []) => { return SavedObjectsRepository.createRepository( migrator, - new SavedObjectsSchema(this.schemas), - this.setupDeps!.legacyPlugins.pluginExtendedConfig, + this.typeRegistry, kibanaConfig.index, callCluster, extraTypes @@ -335,9 +342,11 @@ export class SavedObjectsService return { migrator, clientProvider, + typeRegistry: this.typeRegistry, getScopedClient: clientProvider.getClient.bind(clientProvider), createScopedRepository: repositoryFactory.createScopedRepository, createInternalRepository: repositoryFactory.createInternalRepository, + createSerializer: () => new SavedObjectsSerializer(this.typeRegistry), }; } @@ -348,18 +357,14 @@ export class SavedObjectsService savedObjectsConfig: SavedObjectsConfigType, migrationsRetryDelay?: number ): KibanaMigrator { - const savedObjectSchemas = new SavedObjectsSchema(this.schemas); const adminClient = this.setupDeps!.elasticsearch.adminClient; return new KibanaMigrator({ - savedObjectSchemas, - savedObjectMappings: this.mappings, - savedObjectMigrations: this.migrations, - savedObjectValidations: this.validations, + typeRegistry: this.typeRegistry, logger: this.logger, kibanaVersion: this.coreContext.env.packageInfo.version, - config: this.setupDeps!.legacyPlugins.pluginExtendedConfig, savedObjectsConfig, + savedObjectValidations: this.validations, kibanaConfig, callCluster: migrationsRetryCallCluster( adminClient.callAsInternalUser, diff --git a/src/core/server/saved_objects/saved_objects_type_registry.mock.ts b/src/core/server/saved_objects/saved_objects_type_registry.mock.ts new file mode 100644 index 0000000000000..6e11920db6b7d --- /dev/null +++ b/src/core/server/saved_objects/saved_objects_type_registry.mock.ts @@ -0,0 +1,41 @@ +/* + * 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 { ISavedObjectTypeRegistry } from './saved_objects_type_registry'; + +const createRegistryMock = (): jest.Mocked => { + const mock = { + registerType: jest.fn(), + getType: jest.fn(), + getAllTypes: jest.fn(), + isNamespaceAgnostic: jest.fn(), + isHidden: jest.fn(), + getIndex: jest.fn(), + }; + + mock.getIndex.mockReturnValue('.kibana-test'); + mock.isHidden.mockReturnValue(false); + mock.isNamespaceAgnostic.mockImplementation((type: string) => type === 'global'); + + return mock; +}; + +export const typeRegistryMock = { + create: createRegistryMock, +}; diff --git a/src/core/server/saved_objects/saved_objects_type_registry.test.ts b/src/core/server/saved_objects/saved_objects_type_registry.test.ts new file mode 100644 index 0000000000000..4268ab7718f8d --- /dev/null +++ b/src/core/server/saved_objects/saved_objects_type_registry.test.ts @@ -0,0 +1,215 @@ +/* + * 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 { SavedObjectTypeRegistry } from './saved_objects_type_registry'; +import { SavedObjectsType } from './types'; + +const createType = (type: Partial): SavedObjectsType => ({ + name: 'unknown', + hidden: false, + namespaceAgnostic: false, + mappings: { properties: {} }, + migrations: {}, + ...type, +}); + +describe('SavedObjectTypeRegistry', () => { + let registry: SavedObjectTypeRegistry; + + beforeEach(() => { + registry = new SavedObjectTypeRegistry(); + }); + + it('allows to register types', () => { + registry.registerType(createType({ name: 'typeA' })); + registry.registerType(createType({ name: 'typeB' })); + registry.registerType(createType({ name: 'typeC' })); + + expect( + registry + .getAllTypes() + .map(type => type.name) + .sort() + ).toEqual(['typeA', 'typeB', 'typeC']); + }); + + it('throws when trying to register the same type twice', () => { + registry.registerType(createType({ name: 'typeA' })); + registry.registerType(createType({ name: 'typeB' })); + expect(() => { + registry.registerType(createType({ name: 'typeA' })); + }).toThrowErrorMatchingInlineSnapshot(`"Type 'typeA' is already registered"`); + }); + + describe('#getType', () => { + it(`retrieve a type by it's name`, () => { + const typeA = createType({ name: 'typeA' }); + const typeB = createType({ name: 'typeB' }); + registry.registerType(typeA); + registry.registerType(typeB); + registry.registerType(createType({ name: 'typeC' })); + + expect(registry.getType('typeA')).toEqual(typeA); + expect(registry.getType('typeB')).toEqual(typeB); + expect(registry.getType('unknownType')).toBeUndefined(); + }); + + it('forbids to mutate the registered types', () => { + registry.registerType( + createType({ + name: 'typeA', + mappings: { + properties: { + someField: { type: 'text' }, + }, + }, + }) + ); + + const typeA = registry.getType('typeA')!; + + expect(() => { + typeA.migrations = {}; + }).toThrow(); + expect(() => { + typeA.name = 'foo'; + }).toThrow(); + expect(() => { + typeA.mappings.properties = {}; + }).toThrow(); + expect(() => { + typeA.indexPattern = '.overrided'; + }).toThrow(); + }); + }); + + describe('#getAllTypes', () => { + it('returns all registered types', () => { + const typeA = createType({ name: 'typeA' }); + const typeB = createType({ name: 'typeB' }); + const typeC = createType({ name: 'typeC' }); + registry.registerType(typeA); + registry.registerType(typeB); + + const registered = registry.getAllTypes(); + expect(registered.length).toEqual(2); + expect(registered).toContainEqual(typeA); + expect(registered).toContainEqual(typeB); + expect(registered).not.toContainEqual(typeC); + }); + + it('forbids to mutate the registered types', () => { + registry.registerType( + createType({ + name: 'typeA', + mappings: { + properties: { + someField: { type: 'text' }, + }, + }, + }) + ); + registry.registerType( + createType({ + name: 'typeB', + migrations: { + '1.0.0': jest.fn(), + }, + }) + ); + + const typeA = registry.getType('typeA')!; + const typeB = registry.getType('typeB')!; + + expect(() => { + typeA.migrations = {}; + }).toThrow(); + expect(() => { + typeA.name = 'foo'; + }).toThrow(); + expect(() => { + typeB.mappings.properties = {}; + }).toThrow(); + expect(() => { + typeB.indexPattern = '.overrided'; + }).toThrow(); + }); + + it('does not mutate the registered types when altering the list', () => { + registry.registerType(createType({ name: 'typeA' })); + registry.registerType(createType({ name: 'typeB' })); + registry.registerType(createType({ name: 'typeC' })); + + const types = registry.getAllTypes(); + types.splice(0, 3); + + expect(registry.getAllTypes().length).toEqual(3); + }); + }); + + describe('#isNamespaceAgnostic', () => { + it('returns correct value for the type', () => { + registry.registerType(createType({ name: 'typeA', namespaceAgnostic: true })); + registry.registerType(createType({ name: 'typeB', namespaceAgnostic: false })); + + expect(registry.isNamespaceAgnostic('typeA')).toEqual(true); + expect(registry.isNamespaceAgnostic('typeB')).toEqual(false); + }); + it('returns false when the type is not registered', () => { + registry.registerType(createType({ name: 'typeA', namespaceAgnostic: true })); + registry.registerType(createType({ name: 'typeB', namespaceAgnostic: false })); + + expect(registry.isNamespaceAgnostic('unknownType')).toEqual(false); + }); + }); + + describe('#isHidden', () => { + it('returns correct value for the type', () => { + registry.registerType(createType({ name: 'typeA', hidden: true })); + registry.registerType(createType({ name: 'typeB', hidden: false })); + + expect(registry.isHidden('typeA')).toEqual(true); + expect(registry.isHidden('typeB')).toEqual(false); + }); + it('returns false when the type is not registered', () => { + registry.registerType(createType({ name: 'typeA', hidden: true })); + registry.registerType(createType({ name: 'typeB', hidden: false })); + + expect(registry.isHidden('unknownType')).toEqual(false); + }); + }); + + describe('#getIndex', () => { + it('returns correct value for the type', () => { + registry.registerType(createType({ name: 'typeA', indexPattern: '.custom-index' })); + registry.registerType(createType({ name: 'typeB', indexPattern: '.another-index' })); + registry.registerType(createType({ name: 'typeWithNoIndex' })); + + expect(registry.getIndex('typeA')).toEqual('.custom-index'); + expect(registry.getIndex('typeB')).toEqual('.another-index'); + expect(registry.getIndex('typeWithNoIndex')).toBeUndefined(); + }); + it('returns undefined when the type is not registered', () => { + registry.registerType(createType({ name: 'typeA', namespaceAgnostic: true })); + registry.registerType(createType({ name: 'typeB', namespaceAgnostic: false })); + + expect(registry.getIndex('unknownType')).toBeUndefined(); + }); + }); +}); diff --git a/src/core/server/saved_objects/saved_objects_type_registry.ts b/src/core/server/saved_objects/saved_objects_type_registry.ts new file mode 100644 index 0000000000000..3f26d696831fd --- /dev/null +++ b/src/core/server/saved_objects/saved_objects_type_registry.ts @@ -0,0 +1,86 @@ +/* + * 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 { deepFreeze } from '../../utils'; +import { SavedObjectsType } from './types'; + +/** + * See {@link SavedObjectTypeRegistry} for documentation. + * + * @internal + * */ +export type ISavedObjectTypeRegistry = PublicMethodsOf; + +/** + * Registry holding information about all the registered {@link SavedObjectsType | savedObject types}. + * + * @internal + */ +export class SavedObjectTypeRegistry { + private readonly types = new Map(); + + /** + * Register a {@link SavedObjectsType | type} inside the registry. + * A type can only be registered once. subsequent calls with the same type name will throw an error. + */ + public registerType(type: SavedObjectsType) { + if (this.types.has(type.name)) { + throw new Error(`Type '${type.name}' is already registered`); + } + this.types.set(type.name, deepFreeze(type)); + } + + /** + * Return the {@link SavedObjectsType | type} definition for given type name. + */ + public getType(type: string) { + return this.types.get(type); + } + + /** + * Return all {@link SavedObjectsType | types} currently registered. + */ + public getAllTypes() { + return [...this.types.values()]; + } + + /** + * Returns the `namespaceAgnostic` property for given type, or `false` if + * the type is not registered. + */ + public isNamespaceAgnostic(type: string) { + return this.types.get(type)?.namespaceAgnostic ?? false; + } + + /** + * Returns the `hidden` property for given type, or `false` if + * the type is not registered. + */ + public isHidden(type: string) { + return this.types.get(type)?.hidden ?? false; + } + + /** + * Returns the `indexPattern` property for given type, or `undefined` if + * the type is not registered. + */ + public getIndex(type: string) { + return this.types.get(type)?.indexPattern; + } +} diff --git a/src/core/server/saved_objects/schema/schema.ts b/src/core/server/saved_objects/schema/schema.ts index 00c4939233318..17ca406ea109a 100644 --- a/src/core/server/saved_objects/schema/schema.ts +++ b/src/core/server/saved_objects/schema/schema.ts @@ -19,6 +19,10 @@ import { LegacyConfig } from '../../legacy'; +/** + * @deprecated + * @internal + **/ interface SavedObjectsSchemaTypeDefinition { isNamespaceAgnostic: boolean; hidden?: boolean; @@ -26,12 +30,18 @@ interface SavedObjectsSchemaTypeDefinition { convertToAliasScript?: string; } -/** @internal */ +/** + * @deprecated + * @internal + **/ export interface SavedObjectsSchemaDefinition { - [key: string]: SavedObjectsSchemaTypeDefinition; + [type: string]: SavedObjectsSchemaTypeDefinition; } -/** @internal */ +/** + * @deprecated This is only used by the {@link SavedObjectsLegacyService | legacy savedObjects service} + * @internal + **/ export class SavedObjectsSchema { private readonly definition?: SavedObjectsSchemaDefinition; constructor(schemaDefinition?: SavedObjectsSchemaDefinition) { @@ -46,7 +56,6 @@ export class SavedObjectsSchema { return false; } - // TODO: Remove dependency on config when we move SavedObjectsSchema to NP public getIndexForType(config: LegacyConfig, type: string): string | undefined { if (this.definition != null && this.definition.hasOwnProperty(type)) { const { indexPattern } = this.definition[type]; diff --git a/src/core/server/saved_objects/serialization/index.ts b/src/core/server/saved_objects/serialization/index.ts index 217ffe7129e94..f7f4e75704341 100644 --- a/src/core/server/saved_objects/serialization/index.ts +++ b/src/core/server/saved_objects/serialization/index.ts @@ -22,167 +22,5 @@ * the raw document format as stored in ElasticSearch. */ -/* eslint-disable @typescript-eslint/camelcase */ - -import uuid from 'uuid'; -import { SavedObjectsSchema } from '../schema'; -import { decodeVersion, encodeVersion } from '../version'; -import { SavedObjectsMigrationVersion, SavedObjectReference } from '../types'; - -/** - * A raw document as represented directly in the saved object index. - */ -export interface RawDoc { - _id: string; - _source: any; - _type?: string; - _seq_no?: number; - _primary_term?: number; -} - -/** - * A saved object type definition that allows for miscellaneous, unknown - * properties, as current discussions around security, ACLs, etc indicate - * that future props are likely to be added. Migrations support this - * scenario out of the box. - */ -interface SavedObjectDoc { - attributes: object; - id?: string; // NOTE: SavedObjectDoc is used for uncreated objects where `id` is optional - type: string; - namespace?: string; - migrationVersion?: SavedObjectsMigrationVersion; - version?: string; - updated_at?: string; - - [rootProp: string]: any; -} - -interface Referencable { - references: SavedObjectReference[]; -} - -/** - * We want to have two types, one that guarantees a "references" attribute - * will exist and one that allows it to be null. Since we're not migrating - * all the saved objects to have a "references" array, we need to support - * the scenarios where it may be missing (ex migrations). - */ -export type RawSavedObjectDoc = SavedObjectDoc & Partial; -export type SanitizedSavedObjectDoc = SavedObjectDoc & Referencable; - -function assertNonEmptyString(value: string, name: string) { - if (!value || typeof value !== 'string') { - throw new TypeError(`Expected "${value}" to be a ${name}`); - } -} - -/** @internal */ -export class SavedObjectsSerializer { - private readonly schema: SavedObjectsSchema; - - constructor(schema: SavedObjectsSchema) { - this.schema = schema; - } - /** - * Determines whether or not the raw document can be converted to a saved object. - * - * @param {RawDoc} rawDoc - The raw ES document to be tested - */ - public isRawSavedObject(rawDoc: RawDoc) { - const { type, namespace } = rawDoc._source; - const namespacePrefix = - namespace && !this.schema.isNamespaceAgnostic(type) ? `${namespace}:` : ''; - return ( - type && - rawDoc._id.startsWith(`${namespacePrefix}${type}:`) && - rawDoc._source.hasOwnProperty(type) - ); - } - - /** - * Converts a document from the format that is stored in elasticsearch to the saved object client format. - * - * @param {RawDoc} rawDoc - The raw ES document to be converted to saved object format. - */ - public rawToSavedObject(doc: RawDoc): SanitizedSavedObjectDoc { - const { _id, _source, _seq_no, _primary_term } = doc; - const { type, namespace } = _source; - - const version = - _seq_no != null || _primary_term != null - ? encodeVersion(_seq_no!, _primary_term!) - : undefined; - - return { - type, - id: this.trimIdPrefix(namespace, type, _id), - ...(namespace && !this.schema.isNamespaceAgnostic(type) && { namespace }), - attributes: _source[type], - references: _source.references || [], - ...(_source.migrationVersion && { migrationVersion: _source.migrationVersion }), - ...(_source.updated_at && { updated_at: _source.updated_at }), - ...(version && { version }), - }; - } - - /** - * Converts a document from the saved object client format to the format that is stored in elasticsearch. - * - * @param {SanitizedSavedObjectDoc} savedObj - The saved object to be converted to raw ES format. - */ - public savedObjectToRaw(savedObj: SanitizedSavedObjectDoc): RawDoc { - const { - id, - type, - namespace, - attributes, - migrationVersion, - updated_at, - version, - references, - } = savedObj; - const source = { - [type]: attributes, - type, - references, - ...(namespace && !this.schema.isNamespaceAgnostic(type) && { namespace }), - ...(migrationVersion && { migrationVersion }), - ...(updated_at && { updated_at }), - }; - - return { - _id: this.generateRawId(namespace, type, id), - _source: source, - ...(version != null && decodeVersion(version)), - }; - } - - /** - * Given a saved object type and id, generates the compound id that is stored in the raw document. - * - * @param {string} namespace - The namespace of the saved object - * @param {string} type - The saved object type - * @param {string} id - The id of the saved object - */ - public generateRawId(namespace: string | undefined, type: string, id?: string) { - const namespacePrefix = - namespace && !this.schema.isNamespaceAgnostic(type) ? `${namespace}:` : ''; - return `${namespacePrefix}${type}:${id || uuid.v1()}`; - } - - private trimIdPrefix(namespace: string | undefined, type: string, id: string) { - assertNonEmptyString(id, 'document id'); - assertNonEmptyString(type, 'saved object type'); - - const namespacePrefix = - namespace && !this.schema.isNamespaceAgnostic(type) ? `${namespace}:` : ''; - const prefix = `${namespacePrefix}${type}:`; - - if (!id.startsWith(prefix)) { - return id; - } - - return id.slice(prefix.length); - } -} +export { SavedObjectUnsanitizedDoc, SavedObjectSanitizedDoc, SavedObjectsRawDoc } from './types'; +export { SavedObjectsSerializer } from './serializer'; diff --git a/src/core/server/saved_objects/serialization/serialization.test.ts b/src/core/server/saved_objects/serialization/serializer.test.ts similarity index 79% rename from src/core/server/saved_objects/serialization/serialization.test.ts rename to src/core/server/saved_objects/serialization/serializer.test.ts index e8bcdde73fcf4..8f09b25bb3908 100644 --- a/src/core/server/saved_objects/serialization/serialization.test.ts +++ b/src/core/server/saved_objects/serialization/serializer.test.ts @@ -18,14 +18,21 @@ */ import _ from 'lodash'; -import { SavedObjectsSerializer } from '.'; -import { SavedObjectsSchema } from '../schema'; +import { SavedObjectsSerializer } from './serializer'; +import { typeRegistryMock } from '../saved_objects_type_registry.mock'; import { encodeVersion } from '../version'; describe('saved object conversion', () => { + let typeRegistry: ReturnType; + + beforeEach(() => { + typeRegistry = typeRegistryMock.create(); + typeRegistry.isNamespaceAgnostic.mockReturnValue(false); + }); + describe('#rawToSavedObject', () => { test('it copies the _source.type property to type', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -36,7 +43,7 @@ describe('saved object conversion', () => { }); test('it copies the _source.references property to references', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -54,7 +61,7 @@ describe('saved object conversion', () => { }); test('if specified it copies the _source.migrationVersion property to migrationVersion', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -72,7 +79,7 @@ describe('saved object conversion', () => { }); test(`if _source.migrationVersion is unspecified it doesn't set migrationVersion`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -83,8 +90,8 @@ describe('saved object conversion', () => { }); test('it converts the id and type properties, and retains migrationVersion', () => { - const now = new Date(); - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const now = String(new Date()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'hello:world', _seq_no: 3, @@ -121,7 +128,7 @@ describe('saved object conversion', () => { }); test(`if version is unspecified it doesn't set version`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -133,7 +140,7 @@ describe('saved object conversion', () => { }); test(`if specified it encodes _seq_no and _primary_term to version`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _seq_no: 4, @@ -147,7 +154,7 @@ describe('saved object conversion', () => { }); test(`if only _seq_no is specified it throws`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect(() => serializer.rawToSavedObject({ _id: 'foo:bar', @@ -161,7 +168,7 @@ describe('saved object conversion', () => { }); test(`if only _primary_term is throws`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect(() => serializer.rawToSavedObject({ _id: 'foo:bar', @@ -175,7 +182,7 @@ describe('saved object conversion', () => { }); test('if specified it copies the _source.updated_at property to updated_at', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const now = Date(); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', @@ -188,7 +195,7 @@ describe('saved object conversion', () => { }); test(`if _source.updated_at is unspecified it doesn't set updated_at`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -199,7 +206,7 @@ describe('saved object conversion', () => { }); test('it does not pass unknown properties through', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'universe', _source: { @@ -221,7 +228,7 @@ describe('saved object conversion', () => { }); test('it does not create attributes if [type] is missing', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'universe', _source: { @@ -236,7 +243,7 @@ describe('saved object conversion', () => { }); test('it fails for documents which do not specify a type', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect(() => serializer.rawToSavedObject({ _id: 'universe', @@ -244,13 +251,13 @@ describe('saved object conversion', () => { hello: { world: 'earth', }, - }, + } as any, }) ).toThrow(/Expected "undefined" to be a saved object type/); }); test('it is complimentary with savedObjectToRaw', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const raw = { _id: 'foo-namespace:foo:bar', _primary_term: 24, @@ -266,7 +273,7 @@ describe('saved object conversion', () => { bar: '9.8.7', }, namespace: 'foo-namespace', - updated_at: new Date(), + updated_at: String(new Date()), references: [], }, }; @@ -277,7 +284,7 @@ describe('saved object conversion', () => { }); test('it handles unprefixed ids', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'universe', _source: { @@ -290,7 +297,7 @@ describe('saved object conversion', () => { describe('namespaced type without a namespace', () => { test(`removes type prefix from _id`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -302,7 +309,7 @@ describe('saved object conversion', () => { }); test(`if prefixed by random prefix and type it copies _id to id`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'random:foo:bar', _source: { @@ -314,7 +321,7 @@ describe('saved object conversion', () => { }); test(`doesn't specify namespace`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -328,7 +335,7 @@ describe('saved object conversion', () => { describe('namespaced type with a namespace', () => { test(`removes type and namespace prefix from _id`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'baz:foo:bar', _source: { @@ -341,7 +348,7 @@ describe('saved object conversion', () => { }); test(`if prefixed by only type it copies _id to id`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -354,7 +361,7 @@ describe('saved object conversion', () => { }); test(`if prefixed by random prefix and type it copies _id to id`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'random:foo:bar', _source: { @@ -367,7 +374,7 @@ describe('saved object conversion', () => { }); test(`copies _source.namespace to namespace`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'baz:foo:bar', _source: { @@ -381,10 +388,12 @@ describe('saved object conversion', () => { }); describe('namespace agnostic type with a namespace', () => { + beforeEach(() => { + typeRegistry.isNamespaceAgnostic.mockReturnValue(true); + }); + test(`removes type prefix from _id`, () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ foo: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'foo:bar', _source: { @@ -397,9 +406,7 @@ describe('saved object conversion', () => { }); test(`if prefixed by namespace and type it copies _id to id`, () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ foo: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'baz:foo:bar', _source: { @@ -412,9 +419,7 @@ describe('saved object conversion', () => { }); test(`doesn't copy _source.namespace to namespace`, () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ foo: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.rawToSavedObject({ _id: 'baz:foo:bar', _source: { @@ -430,7 +435,7 @@ describe('saved object conversion', () => { describe('#savedObjectToRaw', () => { test('it copies the type property to _source.type and uses the ROOT_TYPE as _type', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: 'foo', attributes: {}, @@ -440,7 +445,7 @@ describe('saved object conversion', () => { }); test('it copies the references property to _source.references', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ id: '1', type: 'foo', @@ -457,7 +462,7 @@ describe('saved object conversion', () => { }); test('if specified it copies the updated_at property to _source.updated_at', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const now = new Date(); const actual = serializer.savedObjectToRaw({ type: '', @@ -469,7 +474,7 @@ describe('saved object conversion', () => { }); test(`if unspecified it doesn't add updated_at property to _source`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: '', attributes: {}, @@ -479,7 +484,7 @@ describe('saved object conversion', () => { }); test('it copies the migrationVersion property to _source.migrationVersion', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: '', attributes: {}, @@ -496,7 +501,7 @@ describe('saved object conversion', () => { }); test(`if unspecified it doesn't add migrationVersion property to _source`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: '', attributes: {}, @@ -506,7 +511,7 @@ describe('saved object conversion', () => { }); test('it decodes the version property to _seq_no and _primary_term', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: '', attributes: {}, @@ -518,7 +523,7 @@ describe('saved object conversion', () => { }); test(`if unspecified it doesn't add _seq_no or _primary_term properties`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: '', attributes: {}, @@ -529,7 +534,7 @@ describe('saved object conversion', () => { }); test(`if version invalid it throws`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect(() => serializer.savedObjectToRaw({ type: '', @@ -540,7 +545,7 @@ describe('saved object conversion', () => { }); test('it copies attributes to _source[type]', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: 'foo', attributes: { @@ -557,7 +562,7 @@ describe('saved object conversion', () => { describe('namespaced type without a namespace', () => { test('generates an id prefixed with type, if no id is specified', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const v1 = serializer.savedObjectToRaw({ type: 'foo', attributes: { @@ -577,7 +582,7 @@ describe('saved object conversion', () => { }); test(`doesn't specify _source.namespace`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: '', attributes: {}, @@ -589,7 +594,7 @@ describe('saved object conversion', () => { describe('namespaced type with a namespace', () => { test('generates an id prefixed with namespace and type, if no id is specified', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const v1 = serializer.savedObjectToRaw({ type: 'foo', namespace: 'bar', @@ -611,7 +616,7 @@ describe('saved object conversion', () => { }); test(`it copies namespace to _source.namespace`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: 'foo', attributes: {}, @@ -623,10 +628,12 @@ describe('saved object conversion', () => { }); describe('namespace agnostic type with a namespace', () => { + beforeEach(() => { + typeRegistry.isNamespaceAgnostic.mockReturnValue(true); + }); + test('generates an id prefixed with type, if no id is specified', () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ foo: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); const v1 = serializer.savedObjectToRaw({ type: 'foo', namespace: 'bar', @@ -648,9 +655,7 @@ describe('saved object conversion', () => { }); test(`doesn't specify _source.namespace`, () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ foo: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); const actual = serializer.savedObjectToRaw({ type: 'foo', namespace: 'bar', @@ -665,7 +670,7 @@ describe('saved object conversion', () => { describe('#isRawSavedObject', () => { describe('namespaced type without a namespace', () => { test('is true if the id is prefixed and the type matches', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', @@ -678,7 +683,7 @@ describe('saved object conversion', () => { }); test('is false if the id is not prefixed', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'world', @@ -691,19 +696,19 @@ describe('saved object conversion', () => { }); test('is false if the type attribute is missing', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', _source: { hello: {}, - }, + } as any, }) ).toBeFalsy(); }); test(`is false if the type prefix omits the :`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'helloworld', @@ -716,7 +721,7 @@ describe('saved object conversion', () => { }); test('is false if the type attribute does not match the id', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', @@ -730,7 +735,7 @@ describe('saved object conversion', () => { }); test('is false if there is no [type] attribute', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', @@ -745,7 +750,7 @@ describe('saved object conversion', () => { describe('namespaced type with a namespace', () => { test('is true if the id is prefixed with type and namespace and the type matches', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'foo:hello:world', @@ -759,7 +764,7 @@ describe('saved object conversion', () => { }); test('is false if the id is not prefixed by anything', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'world', @@ -773,7 +778,7 @@ describe('saved object conversion', () => { }); test('is false if the id is prefixed only with type and the type matches', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', @@ -787,7 +792,7 @@ describe('saved object conversion', () => { }); test('is false if the id is prefixed only with namespace and the namespace matches', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'foo:world', @@ -801,7 +806,7 @@ describe('saved object conversion', () => { }); test(`is false if the id prefix omits the trailing :`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'foo:helloworld', @@ -815,20 +820,20 @@ describe('saved object conversion', () => { }); test('is false if the type attribute is missing', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'foo:hello:world', _source: { hello: {}, namespace: 'foo', - }, + } as any, }) ).toBeFalsy(); }); test('is false if the type attribute does not match the id', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'foo:hello:world', @@ -843,7 +848,7 @@ describe('saved object conversion', () => { }); test('is false if the namespace attribute does not match the id', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'bar:jam:world', @@ -858,7 +863,7 @@ describe('saved object conversion', () => { }); test('is false if there is no [type] attribute', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', @@ -872,11 +877,13 @@ describe('saved object conversion', () => { }); }); - describe('namespace agonstic type with a namespace', () => { + describe('namespace agnostic type with a namespace', () => { + beforeEach(() => { + typeRegistry.isNamespaceAgnostic.mockReturnValue(true); + }); + test('is true if the id is prefixed with type and the type matches', () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ hello: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', @@ -890,9 +897,7 @@ describe('saved object conversion', () => { }); test('is false if the id is not prefixed', () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ hello: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'world', @@ -906,9 +911,7 @@ describe('saved object conversion', () => { }); test('is false if the id is prefixed with type and namespace', () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ hello: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'foo:hello:world', @@ -922,9 +925,7 @@ describe('saved object conversion', () => { }); test(`is false if the type prefix omits the :`, () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ hello: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'helloworld', @@ -938,24 +939,20 @@ describe('saved object conversion', () => { }); test('is false if the type attribute is missing', () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ hello: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', _source: { hello: {}, namespace: 'foo', - }, + } as any, }) ).toBeFalsy(); }); test('is false if the type attribute does not match the id', () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ hello: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', @@ -970,9 +967,7 @@ describe('saved object conversion', () => { }); test('is false if there is no [type] attribute', () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ hello: { isNamespaceAgnostic: true } }) - ); + const serializer = new SavedObjectsSerializer(typeRegistry); expect( serializer.isRawSavedObject({ _id: 'hello:world', @@ -990,13 +985,13 @@ describe('saved object conversion', () => { describe('#generateRawId', () => { describe('namespaced type without a namespace', () => { test('generates an id if none is specified', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const id = serializer.generateRawId('', 'goodbye'); expect(id).toMatch(/goodbye\:[\w-]+$/); }); test('uses the id that is specified', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const id = serializer.generateRawId('', 'hello', 'world'); expect(id).toMatch('hello:world'); }); @@ -1004,13 +999,13 @@ describe('saved object conversion', () => { describe('namespaced type with a namespace', () => { test('generates an id if none is specified and prefixes namespace', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const id = serializer.generateRawId('foo', 'goodbye'); expect(id).toMatch(/foo:goodbye\:[\w-]+$/); }); test('uses the id that is specified and prefixes the namespace', () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const id = serializer.generateRawId('foo', 'hello', 'world'); expect(id).toMatch('foo:hello:world'); }); @@ -1018,15 +1013,15 @@ describe('saved object conversion', () => { describe('namespace agnostic type with a namespace', () => { test(`generates an id if none is specified and doesn't prefix namespace`, () => { - const serializer = new SavedObjectsSerializer( - new SavedObjectsSchema({ foo: { isNamespaceAgnostic: true } }) - ); + typeRegistry.isNamespaceAgnostic.mockReturnValue(true); + + const serializer = new SavedObjectsSerializer(typeRegistry); const id = serializer.generateRawId('foo', 'goodbye'); expect(id).toMatch(/goodbye\:[\w-]+$/); }); test(`uses the id that is specified and doesn't prefix the namespace`, () => { - const serializer = new SavedObjectsSerializer(new SavedObjectsSchema()); + const serializer = new SavedObjectsSerializer(typeRegistry); const id = serializer.generateRawId('foo', 'hello', 'world'); expect(id).toMatch('hello:world'); }); diff --git a/src/core/server/saved_objects/serialization/serializer.ts b/src/core/server/saved_objects/serialization/serializer.ts new file mode 100644 index 0000000000000..99d6b0c6b59f9 --- /dev/null +++ b/src/core/server/saved_objects/serialization/serializer.ts @@ -0,0 +1,151 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/camelcase */ + +import uuid from 'uuid'; +import { decodeVersion, encodeVersion } from '../version'; +import { ISavedObjectTypeRegistry } from '../saved_objects_type_registry'; +import { SavedObjectsRawDoc, SavedObjectSanitizedDoc } from './types'; + +/** + * A serializer that can be used to manually convert {@link SavedObjectsRawDoc | raw} or + * {@link SavedObjectSanitizedDoc | sanitized} documents to the other kind. + * + * @remarks Serializer instances should only be created and accessed by calling {@link SavedObjectsServiceStart.createSerializer} + * + * @public + */ +export class SavedObjectsSerializer { + private readonly registry: ISavedObjectTypeRegistry; + + /** + * @internal + */ + constructor(registry: ISavedObjectTypeRegistry) { + this.registry = registry; + } + /** + * Determines whether or not the raw document can be converted to a saved object. + * + * @param {SavedObjectsRawDoc} rawDoc - The raw ES document to be tested + */ + public isRawSavedObject(rawDoc: SavedObjectsRawDoc) { + const { type, namespace } = rawDoc._source; + const namespacePrefix = + namespace && !this.registry.isNamespaceAgnostic(type) ? `${namespace}:` : ''; + return Boolean( + type && + rawDoc._id.startsWith(`${namespacePrefix}${type}:`) && + rawDoc._source.hasOwnProperty(type) + ); + } + + /** + * Converts a document from the format that is stored in elasticsearch to the saved object client format. + * + * @param {SavedObjectsRawDoc} doc - The raw ES document to be converted to saved object format. + */ + public rawToSavedObject(doc: SavedObjectsRawDoc): SavedObjectSanitizedDoc { + const { _id, _source, _seq_no, _primary_term } = doc; + const { type, namespace } = _source; + + const version = + _seq_no != null || _primary_term != null + ? encodeVersion(_seq_no!, _primary_term!) + : undefined; + + return { + type, + id: this.trimIdPrefix(namespace, type, _id), + ...(namespace && !this.registry.isNamespaceAgnostic(type) && { namespace }), + attributes: _source[type], + references: _source.references || [], + ...(_source.migrationVersion && { migrationVersion: _source.migrationVersion }), + ...(_source.updated_at && { updated_at: _source.updated_at }), + ...(version && { version }), + }; + } + + /** + * Converts a document from the saved object client format to the format that is stored in elasticsearch. + * + * @param {SavedObjectSanitizedDoc} savedObj - The saved object to be converted to raw ES format. + */ + public savedObjectToRaw(savedObj: SavedObjectSanitizedDoc): SavedObjectsRawDoc { + const { + id, + type, + namespace, + attributes, + migrationVersion, + updated_at, + version, + references, + } = savedObj; + const source = { + [type]: attributes, + type, + references, + ...(namespace && !this.registry.isNamespaceAgnostic(type) && { namespace }), + ...(migrationVersion && { migrationVersion }), + ...(updated_at && { updated_at }), + }; + + return { + _id: this.generateRawId(namespace, type, id), + _source: source, + ...(version != null && decodeVersion(version)), + }; + } + + /** + * Given a saved object type and id, generates the compound id that is stored in the raw document. + * + * @param {string} namespace - The namespace of the saved object + * @param {string} type - The saved object type + * @param {string} id - The id of the saved object + */ + public generateRawId(namespace: string | undefined, type: string, id?: string) { + const namespacePrefix = + namespace && !this.registry.isNamespaceAgnostic(type) ? `${namespace}:` : ''; + return `${namespacePrefix}${type}:${id || uuid.v1()}`; + } + + private trimIdPrefix(namespace: string | undefined, type: string, id: string) { + assertNonEmptyString(id, 'document id'); + assertNonEmptyString(type, 'saved object type'); + + const namespacePrefix = + namespace && !this.registry.isNamespaceAgnostic(type) ? `${namespace}:` : ''; + const prefix = `${namespacePrefix}${type}:`; + + if (!id.startsWith(prefix)) { + return id; + } + + return id.slice(prefix.length); + } +} + +function assertNonEmptyString(value: string, name: string) { + if (!value || typeof value !== 'string') { + throw new TypeError(`Expected "${value}" to be a ${name}`); + } +} diff --git a/src/core/server/saved_objects/serialization/types.ts b/src/core/server/saved_objects/serialization/types.ts new file mode 100644 index 0000000000000..aaf6f45c244ec --- /dev/null +++ b/src/core/server/saved_objects/serialization/types.ts @@ -0,0 +1,79 @@ +/* + * 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 { SavedObjectsMigrationVersion, SavedObjectReference } from '../types'; + +/** + * A raw document as represented directly in the saved object index. + * + * @public + */ +export interface SavedObjectsRawDoc { + _id: string; + _source: SavedObjectsRawDocSource; + _type?: string; + _seq_no?: number; + _primary_term?: number; +} + +/** @public */ +export interface SavedObjectsRawDocSource { + type: string; + namespace?: string; + migrationVersion?: SavedObjectsMigrationVersion; + updated_at?: string; + references?: SavedObjectReference[]; + + [typeMapping: string]: any; +} + +/** + * A saved object type definition that allows for miscellaneous, unknown + * properties, as current discussions around security, ACLs, etc indicate + * that future props are likely to be added. Migrations support this + * scenario out of the box. + */ +interface SavedObjectDoc { + attributes: object; + id?: string; // NOTE: SavedObjectDoc is used for uncreated objects where `id` is optional + type: string; + namespace?: string; + migrationVersion?: SavedObjectsMigrationVersion; + version?: string; + updated_at?: string; + + [rootProp: string]: any; +} + +interface Referencable { + references: SavedObjectReference[]; +} + +/** + * We want to have two types, one that guarantees a "references" attribute + * will exist and one that allows it to be null. Since we're not migrating + * all the saved objects to have a "references" array, we need to support + * the scenarios where it may be missing (ex migrations). + * + * @public + */ +export type SavedObjectUnsanitizedDoc = SavedObjectDoc & Partial; + +/** @public */ +export type SavedObjectSanitizedDoc = SavedObjectDoc & Referencable; diff --git a/src/core/server/saved_objects/service/lib/repository.test.js b/src/core/server/saved_objects/service/lib/repository.test.js index 6171faa7a617c..2e5eeec04e0a8 100644 --- a/src/core/server/saved_objects/service/lib/repository.test.js +++ b/src/core/server/saved_objects/service/lib/repository.test.js @@ -21,10 +21,9 @@ import _ from 'lodash'; import { SavedObjectsRepository } from './repository'; import * as getSearchDslNS from './search_dsl/search_dsl'; import { SavedObjectsErrorHelpers } from './errors'; -import { SavedObjectsSchema } from '../../schema'; import { SavedObjectsSerializer } from '../../serialization'; -import { getRootPropertiesObjects } from '../../mappings/lib/get_root_properties_objects'; import { encodeHitVersion } from '../../version'; +import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; jest.mock('./search_dsl/search_dsl', () => ({ getSearchDsl: jest.fn() })); @@ -35,6 +34,7 @@ describe('SavedObjectsRepository', () => { let callAdminCluster; let savedObjectsRepository; let migrator; + const mockTimestamp = '2017-08-14T15:49:14.886Z'; const mockTimestampFields = { updated_at: mockTimestamp }; const mockVersionProps = { _seq_no: 1, _primary_term: 1 }; @@ -240,12 +240,95 @@ describe('SavedObjectsRepository', () => { }, }; - const schema = new SavedObjectsSchema({ - globaltype: { isNamespaceAgnostic: true }, - foo: { isNamespaceAgnostic: true }, - bar: { isNamespaceAgnostic: true }, - baz: { indexPattern: 'beats' }, - hiddenType: { isNamespaceAgnostic: true, hidden: true }, + const typeRegistry = new SavedObjectTypeRegistry(); + typeRegistry.registerType({ + name: 'config', + hidden: false, + namespaceAgnostic: false, + mappings: { + properties: { + type: 'keyword', + }, + }, + }); + typeRegistry.registerType({ + name: 'index-pattern', + hidden: false, + namespaceAgnostic: false, + mappings: { + properties: { + someField: { + type: 'keyword', + }, + }, + }, + }); + typeRegistry.registerType({ + name: 'dashboard', + hidden: false, + namespaceAgnostic: false, + mappings: { + properties: { + otherField: { + type: 'keyword', + }, + }, + }, + }); + typeRegistry.registerType({ + name: 'globaltype', + hidden: false, + namespaceAgnostic: true, + mappings: { + properties: { + yetAnotherField: { + type: 'keyword', + }, + }, + }, + }); + typeRegistry.registerType({ + name: 'foo', + hidden: false, + namespaceAgnostic: true, + mappings: { + properties: { + type: 'keyword', + }, + }, + }); + typeRegistry.registerType({ + name: 'bar', + hidden: false, + namespaceAgnostic: true, + mappings: { + properties: { + type: 'keyword', + }, + }, + }); + typeRegistry.registerType({ + name: 'baz', + hidden: false, + namespaceAgnostic: false, + indexPattern: 'beats', + mappings: { + properties: { + type: 'keyword', + }, + }, + }); + typeRegistry.registerType({ + name: 'hiddenType', + hidden: true, + namespaceAgnostic: true, + mappings: { + properties: { + someField: { + type: 'keyword', + }, + }, + }, }); beforeEach(() => { @@ -255,16 +338,16 @@ describe('SavedObjectsRepository', () => { runMigrations: async () => ({ status: 'skipped' }), }; - const serializer = new SavedObjectsSerializer(schema); - const allTypes = Object.keys(getRootPropertiesObjects(mappings)); - const allowedTypes = [...new Set(allTypes.filter(type => !schema.isHiddenType(type)))]; + const serializer = new SavedObjectsSerializer(typeRegistry); + const allTypes = typeRegistry.getAllTypes().map(type => type.name); + const allowedTypes = [...new Set(allTypes.filter(type => !typeRegistry.isHidden(type)))]; savedObjectsRepository = new SavedObjectsRepository({ index: '.kibana-test', mappings, callCluster: callAdminCluster, migrator, - schema, + typeRegistry, serializer, allowedTypes, }); @@ -1171,7 +1254,7 @@ describe('SavedObjectsRepository', () => { expect(result).toEqual(deleteByQueryResults); expect(callAdminCluster).toHaveBeenCalledTimes(1); - expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, schema, { + expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, typeRegistry, { namespace: 'my-namespace', type: ['config', 'baz', 'index-pattern', 'dashboard'], }); @@ -1261,7 +1344,11 @@ describe('SavedObjectsRepository', () => { await savedObjectsRepository.find(relevantOpts); expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledTimes(1); - expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, schema, relevantOpts); + expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith( + mappings, + typeRegistry, + relevantOpts + ); }); it('accepts KQL filter and passes keuryNode to getSearchDsl', async () => { diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index 70b8b2878c15b..b485b8dfe398c 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -27,9 +27,12 @@ import { includedFields } from './included_fields'; import { decorateEsError } from './decorate_es_error'; import { SavedObjectsErrorHelpers } from './errors'; import { decodeRequestVersion, encodeVersion, encodeHitVersion } from '../../version'; -import { SavedObjectsSchema } from '../../schema'; import { KibanaMigrator } from '../../migrations'; -import { SavedObjectsSerializer, SanitizedSavedObjectDoc, RawDoc } from '../../serialization'; +import { + SavedObjectsSerializer, + SavedObjectSanitizedDoc, + SavedObjectsRawDoc, +} from '../../serialization'; import { SavedObjectsBulkCreateObject, SavedObjectsBulkGetObject, @@ -51,8 +54,8 @@ import { SavedObjectsMigrationVersion, MutatingOperationRefreshSetting, } from '../../types'; +import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; import { validateConvertFilterToKueryNode } from './filter_utils'; -import { LegacyConfig } from '../../../legacy'; // BEWARE: The SavedObjectClient depends on the implementation details of the SavedObjectsRepository // so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient. @@ -75,11 +78,9 @@ const isLeft = (either: Either): either is Left => { export interface SavedObjectsRepositoryOptions { index: string; - /** @deprecated Will be removed once SavedObjectsSchema is exposed from Core */ - config: LegacyConfig; mappings: IndexMapping; callCluster: APICaller; - schema: SavedObjectsSchema; + typeRegistry: SavedObjectTypeRegistry; serializer: SavedObjectsSerializer; migrator: KibanaMigrator; allowedTypes: string[]; @@ -118,9 +119,8 @@ export type ISavedObjectsRepository = Pick !schema.isHiddenType(type)); + const serializer = new SavedObjectsSerializer(typeRegistry); + const visibleTypes = allTypes.filter(type => !typeRegistry.isHidden(type)); const missingTypeMappings = extraTypes.filter(type => !allTypes.includes(type)); if (missingTypeMappings.length > 0) { @@ -158,10 +157,9 @@ export class SavedObjectsRepository { return new injectedConstructor({ index: indexName, - config, migrator, mappings, - schema, + typeRegistry, serializer, allowedTypes, callCluster: retryCallCluster(callCluster), @@ -171,10 +169,9 @@ export class SavedObjectsRepository { private constructor(options: SavedObjectsRepositoryOptions) { const { index, - config, mappings, callCluster, - schema, + typeRegistry, serializer, migrator, allowedTypes = [], @@ -189,9 +186,8 @@ export class SavedObjectsRepository { // to returning them. this._migrator = migrator; this._index = index; - this._config = config; this._mappings = mappings; - this._schema = schema; + this._registry = typeRegistry; if (allowedTypes.length === 0) { throw new Error('Empty or missing types for saved object repository!'); } @@ -201,7 +197,6 @@ export class SavedObjectsRepository { await migrator.runMigrations(); return callCluster(...args); }; - this._schema = schema; this._serializer = serializer; } @@ -250,7 +245,7 @@ export class SavedObjectsRepository { references, }); - const raw = this._serializer.savedObjectToRaw(migrated as SanitizedSavedObjectDoc); + const raw = this._serializer.savedObjectToRaw(migrated as SavedObjectSanitizedDoc); const response = await this._writeToCluster(method, { id: raw._id, @@ -316,7 +311,7 @@ export class SavedObjectsRepository { namespace, updated_at: time, references: object.references || [], - }) as SanitizedSavedObjectDoc + }) as SavedObjectSanitizedDoc ), }; @@ -435,7 +430,7 @@ export class SavedObjectsRepository { const allTypes = Object.keys(getRootPropertiesObjects(this._mappings)); - const typesToDelete = allTypes.filter(type => !this._schema.isNamespaceAgnostic(type)); + const typesToDelete = allTypes.filter(type => !this._registry.isNamespaceAgnostic(type)); const esOptions = { index: this.getIndicesForTypes(typesToDelete), @@ -443,7 +438,7 @@ export class SavedObjectsRepository { refresh, body: { conflicts: 'proceed', - ...getSearchDsl(this._mappings, this._schema, { + ...getSearchDsl(this._mappings, this._registry, { namespace, type: typesToDelete, }), @@ -531,7 +526,7 @@ export class SavedObjectsRepository { rest_total_hits_as_int: true, body: { seq_no_primary_term: true, - ...getSearchDsl(this._mappings, this._schema, { + ...getSearchDsl(this._mappings, this._registry, { search, defaultSearchOperator, searchFields, @@ -562,7 +557,9 @@ export class SavedObjectsRepository { page, per_page: perPage, total: response.hits.total, - saved_objects: response.hits.hits.map((hit: RawDoc) => this._rawToSavedObject(hit)), + saved_objects: response.hits.hits.map((hit: SavedObjectsRawDoc) => + this._rawToSavedObject(hit) + ), }; } @@ -890,7 +887,7 @@ export class SavedObjectsRepository { updated_at: time, }); - const raw = this._serializer.savedObjectToRaw(migrated as SanitizedSavedObjectDoc); + const raw = this._serializer.savedObjectToRaw(migrated as SavedObjectSanitizedDoc); const response = await this._writeToCluster('update', { id: this._serializer.generateRawId(namespace, type, id), @@ -952,7 +949,7 @@ export class SavedObjectsRepository { * @param type - the type */ private getIndexForType(type: string) { - return this._schema.getIndexForType(this._config, type) || this._index; + return this._registry.getIndex(type) || this._index; } /** @@ -964,7 +961,7 @@ export class SavedObjectsRepository { */ private getIndicesForTypes(types: string[]) { const unique = (array: string[]) => [...new Set(array)]; - return unique(types.map(t => this._schema.getIndexForType(this._config, t) || this._index)); + return unique(types.map(t => this.getIndexForType(t))); } private _getCurrentTime() { @@ -975,7 +972,7 @@ export class SavedObjectsRepository { // includes the namespace, and we use this for migrating documents. However, we don't // want the namespace to be returned from the repository, as the repository scopes each // method transparently to the specified namespace. - private _rawToSavedObject(raw: RawDoc): SavedObject { + private _rawToSavedObject(raw: SavedObjectsRawDoc): SavedObject { const savedObject = this._serializer.rawToSavedObject(raw); return omit(savedObject, 'namespace'); } diff --git a/src/core/server/saved_objects/service/lib/repository_create_repository.test.ts b/src/core/server/saved_objects/service/lib/repository_create_repository.test.ts index b3ea056484760..4a87bb1043ca2 100644 --- a/src/core/server/saved_objects/service/lib/repository_create_repository.test.ts +++ b/src/core/server/saved_objects/service/lib/repository_create_repository.test.ts @@ -18,43 +18,54 @@ */ import { SavedObjectsRepository } from './repository'; import { mockKibanaMigrator } from '../../migrations/kibana/kibana_migrator.mock'; -import { SavedObjectsSchema } from '../../schema'; import { KibanaMigrator } from '../../migrations'; -import { LegacyConfig } from '../../../legacy'; +import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry'; + jest.mock('./repository'); const { SavedObjectsRepository: originalRepository } = jest.requireActual('./repository'); describe('SavedObjectsRepository#createRepository', () => { const callAdminCluster = jest.fn(); - const schema = new SavedObjectsSchema({ - nsAgnosticType: { isNamespaceAgnostic: true }, - nsType: { indexPattern: 'beats', isNamespaceAgnostic: false }, - hiddenType: { isNamespaceAgnostic: true, hidden: true }, + + const typeRegistry = new SavedObjectTypeRegistry(); + typeRegistry.registerType({ + name: 'nsAgnosticType', + hidden: false, + namespaceAgnostic: true, + mappings: { + properties: { + name: { type: 'keyword' }, + }, + }, + migrations: {}, + }); + + typeRegistry.registerType({ + name: 'nsType', + hidden: false, + namespaceAgnostic: false, + indexPattern: 'beats', + mappings: { + properties: { + name: { type: 'keyword' }, + }, + }, + migrations: {}, }); - const mappings = [ - { - pluginId: 'testplugin', + typeRegistry.registerType({ + name: 'hiddenType', + hidden: true, + namespaceAgnostic: true, + mappings: { properties: { - nsAgnosticType: { - properties: { - name: { type: 'keyword' }, - }, - }, - nsType: { - properties: { - name: { type: 'keyword' }, - }, - }, - hiddenType: { - properties: { - name: { type: 'keyword' }, - }, - }, + name: { type: 'keyword' }, }, }, - ]; - const migrator = mockKibanaMigrator.create({ savedObjectMappings: mappings }); + migrations: {}, + }); + + const migrator = mockKibanaMigrator.create({ types: typeRegistry.getAllTypes() }); const RepositoryConstructor = (SavedObjectsRepository as unknown) as jest.Mock< SavedObjectsRepository >; @@ -67,8 +78,7 @@ describe('SavedObjectsRepository#createRepository', () => { try { originalRepository.createRepository( (migrator as unknown) as KibanaMigrator, - schema, - {} as LegacyConfig, + typeRegistry, '.kibana-test', callAdminCluster, ['unMappedType1', 'unmappedType2'] @@ -83,8 +93,7 @@ describe('SavedObjectsRepository#createRepository', () => { it('should create a repository without hidden types', () => { const repository = originalRepository.createRepository( (migrator as unknown) as KibanaMigrator, - schema, - {} as LegacyConfig, + typeRegistry, '.kibana-test', callAdminCluster, [], @@ -103,8 +112,7 @@ describe('SavedObjectsRepository#createRepository', () => { it('should create a repository with a unique list of hidden types', () => { const repository = originalRepository.createRepository( (migrator as unknown) as KibanaMigrator, - schema, - {} as LegacyConfig, + typeRegistry, '.kibana-test', callAdminCluster, ['hiddenType', 'hiddenType', 'hiddenType'], diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts index e585953109d2c..b2129765ee426 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts @@ -17,10 +17,11 @@ * under the License. */ -import { schemaMock } from '../../../schema/schema.mock'; +import { typeRegistryMock } from '../../../saved_objects_type_registry.mock'; import { getQueryParams } from './query_params'; -const SCHEMA = schemaMock.create(); +const registry = typeRegistryMock.create(); + const MAPPINGS = { properties: { type: { @@ -85,7 +86,7 @@ const createTypeClause = (type: string, namespace?: string) => { describe('searchDsl/queryParams', () => { describe('no parameters', () => { it('searches for all known types without a namespace specified', () => { - expect(getQueryParams({ mappings: MAPPINGS, schema: SCHEMA })).toEqual({ + expect(getQueryParams({ mappings: MAPPINGS, registry })).toEqual({ query: { bool: { filter: [ @@ -108,9 +109,7 @@ describe('searchDsl/queryParams', () => { describe('namespace', () => { it('filters namespaced types for namespace, and ensures namespace agnostic types have no namespace', () => { - expect( - getQueryParams({ mappings: MAPPINGS, schema: SCHEMA, namespace: 'foo-namespace' }) - ).toEqual({ + expect(getQueryParams({ mappings: MAPPINGS, registry, namespace: 'foo-namespace' })).toEqual({ query: { bool: { filter: [ @@ -134,7 +133,7 @@ describe('searchDsl/queryParams', () => { describe('type (singular, namespaced)', () => { it('includes a terms filter for type and namespace not being specified', () => { expect( - getQueryParams({ mappings: MAPPINGS, schema: SCHEMA, namespace: undefined, type: 'saved' }) + getQueryParams({ mappings: MAPPINGS, registry, namespace: undefined, type: 'saved' }) ).toEqual({ query: { bool: { @@ -155,7 +154,7 @@ describe('searchDsl/queryParams', () => { describe('type (singular, global)', () => { it('includes a terms filter for type and namespace not being specified', () => { expect( - getQueryParams({ mappings: MAPPINGS, schema: SCHEMA, namespace: undefined, type: 'global' }) + getQueryParams({ mappings: MAPPINGS, registry, namespace: undefined, type: 'global' }) ).toEqual({ query: { bool: { @@ -178,7 +177,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: ['saved', 'global'], }) @@ -204,7 +203,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: ['saved', 'global'], }) @@ -230,7 +229,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: undefined, search: 'us*', @@ -270,7 +269,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: undefined, search: 'us*', @@ -310,7 +309,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: ['saved', 'global'], search: 'us*', @@ -346,7 +345,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: ['saved', 'global'], search: 'us*', @@ -382,7 +381,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: undefined, search: 'y*', @@ -419,7 +418,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: undefined, search: 'y*', @@ -456,7 +455,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: undefined, search: 'y*', @@ -503,7 +502,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: undefined, search: 'y*', @@ -540,7 +539,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: undefined, search: 'y*', @@ -577,7 +576,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: undefined, search: 'y*', @@ -624,7 +623,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: ['saved', 'global'], search: 'y*', @@ -657,7 +656,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: ['saved', 'global'], search: 'y*', @@ -690,7 +689,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: undefined, type: ['saved', 'global'], search: 'y*', @@ -726,7 +725,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: ['saved', 'global'], search: 'y*', @@ -759,7 +758,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: ['saved', 'global'], search: 'y*', @@ -792,7 +791,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: ['saved', 'global'], search: 'y*', @@ -828,7 +827,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: ['saved', 'global'], search: 'foo', @@ -902,7 +901,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', type: ['saved', 'global'], search: undefined, @@ -958,7 +957,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', kueryNode: { type: 'function', @@ -1052,7 +1051,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', kueryNode: { type: 'function', @@ -1189,7 +1188,7 @@ describe('searchDsl/queryParams', () => { expect( getQueryParams({ mappings: MAPPINGS, - schema: SCHEMA, + registry, namespace: 'foo-namespace', search: 'y*', searchFields: ['title'], diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts index a1e3ae9620299..3fabad6af08ff 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts @@ -20,7 +20,7 @@ import { esKuery } from '../../../../../../plugins/data/server'; import { getRootPropertiesObjects, IndexMapping } from '../../../mappings'; -import { SavedObjectsSchema } from '../../../schema'; +import { ISavedObjectTypeRegistry } from '../../../saved_objects_type_registry'; /** * Gets the types based on the type. Uses mappings to support @@ -61,8 +61,12 @@ function getFieldsForTypes(types: string[], searchFields?: string[]) { * Gets the clause that will filter for the type in the namespace. * Some types are namespace agnostic, so they must be treated differently. */ -function getClauseForType(schema: SavedObjectsSchema, namespace: string | undefined, type: string) { - if (namespace && !schema.isNamespaceAgnostic(type)) { +function getClauseForType( + registry: ISavedObjectTypeRegistry, + namespace: string | undefined, + type: string +) { + if (namespace && !registry.isNamespaceAgnostic(type)) { return { bool: { must: [{ term: { type } }, { term: { namespace } }], @@ -85,7 +89,7 @@ interface HasReferenceQueryParams { interface QueryParams { mappings: IndexMapping; - schema: SavedObjectsSchema; + registry: ISavedObjectTypeRegistry; namespace?: string; type?: string | string[]; search?: string; @@ -100,7 +104,7 @@ interface QueryParams { */ export function getQueryParams({ mappings, - schema, + registry, namespace, type, search, @@ -140,7 +144,7 @@ export function getQueryParams({ }, ] : undefined, - should: types.map(shouldType => getClauseForType(schema, namespace, shouldType)), + should: types.map(shouldType => getClauseForType(registry, namespace, shouldType)), minimum_should_match: 1, }, }, diff --git a/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.test.ts b/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.test.ts index 97cab3e566d5e..95b7ffd117ee9 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.test.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.test.ts @@ -20,7 +20,7 @@ jest.mock('./query_params'); jest.mock('./sorting_params'); -import { schemaMock } from '../../../schema/schema.mock'; +import { typeRegistryMock } from '../../../saved_objects_type_registry.mock'; import * as queryParamsNS from './query_params'; import { getSearchDsl } from './search_dsl'; import * as sortParamsNS from './sorting_params'; @@ -28,8 +28,8 @@ import * as sortParamsNS from './sorting_params'; const getQueryParams = queryParamsNS.getQueryParams as jest.Mock; const getSortingParams = sortParamsNS.getSortingParams as jest.Mock; -const SCHEMA = schemaMock.create(); -const MAPPINGS = { properties: {} }; +const registry = typeRegistryMock.create(); +const mappings = { properties: {} }; describe('getSearchDsl', () => { afterEach(() => { @@ -40,7 +40,7 @@ describe('getSearchDsl', () => { describe('validation', () => { it('throws when type is not specified', () => { expect(() => { - getSearchDsl(MAPPINGS, SCHEMA, { + getSearchDsl(mappings, registry, { type: undefined as any, sortField: 'title', }); @@ -48,7 +48,7 @@ describe('getSearchDsl', () => { }); it('throws when sortOrder without sortField', () => { expect(() => { - getSearchDsl(MAPPINGS, SCHEMA, { + getSearchDsl(mappings, registry, { type: 'foo', sortOrder: 'desc', }); @@ -70,11 +70,11 @@ describe('getSearchDsl', () => { }, }; - getSearchDsl(MAPPINGS, SCHEMA, opts); + getSearchDsl(mappings, registry, opts); expect(getQueryParams).toHaveBeenCalledTimes(1); expect(getQueryParams).toHaveBeenCalledWith({ - mappings: MAPPINGS, - schema: SCHEMA, + mappings, + registry, namespace: opts.namespace, type: opts.type, search: opts.search, @@ -92,10 +92,10 @@ describe('getSearchDsl', () => { sortOrder: 'baz', }; - getSearchDsl(MAPPINGS, SCHEMA, opts); + getSearchDsl(mappings, registry, opts); expect(getSortingParams).toHaveBeenCalledTimes(1); expect(getSortingParams).toHaveBeenCalledWith( - MAPPINGS, + mappings, opts.type, opts.sortField, opts.sortOrder @@ -105,7 +105,7 @@ describe('getSearchDsl', () => { it('returns combination of getQueryParams and getSortingParams', () => { getQueryParams.mockReturnValue({ a: 'a' }); getSortingParams.mockReturnValue({ b: 'b' }); - expect(getSearchDsl(MAPPINGS, SCHEMA, { type: 'foo' })).toEqual({ a: 'a', b: 'b' }); + expect(getSearchDsl(mappings, registry, { type: 'foo' })).toEqual({ a: 'a', b: 'b' }); }); }); }); diff --git a/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.ts b/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.ts index 1b6e1361bb92a..75ab058a38be9 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/search_dsl.ts @@ -20,11 +20,11 @@ import Boom from 'boom'; import { IndexMapping } from '../../../mappings'; -import { SavedObjectsSchema } from '../../../schema'; import { getQueryParams } from './query_params'; import { getSortingParams } from './sorting_params'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { esKuery } from '../../../../../../plugins/data/server'; +import { ISavedObjectTypeRegistry } from '../../../saved_objects_type_registry'; interface GetSearchDslOptions { type: string | string[]; @@ -43,7 +43,7 @@ interface GetSearchDslOptions { export function getSearchDsl( mappings: IndexMapping, - schema: SavedObjectsSchema, + registry: ISavedObjectTypeRegistry, options: GetSearchDslOptions ) { const { @@ -69,7 +69,7 @@ export function getSearchDsl( return { ...getQueryParams({ mappings, - schema, + registry, namespace, type, search, diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts index a3fe2b937635b..980ba005e0eeb 100644 --- a/src/core/server/saved_objects/types.ts +++ b/src/core/server/saved_objects/types.ts @@ -18,9 +18,8 @@ */ import { SavedObjectsClient } from './service/saved_objects_client'; -import { SavedObjectsMapping } from './mappings'; -import { MigrationDefinition } from './migrations/core/document_migrator'; -import { SavedObjectsSchemaDefinition } from './schema'; +import { SavedObjectsTypeMappingDefinition, SavedObjectsTypeMappingDefinitions } from './mappings'; +import { SavedObjectMigrationMap } from './migrations'; import { PropertyValidators } from './validation'; export { @@ -34,6 +33,7 @@ export { } from './import/types'; import { SavedObjectAttributes } from '../../types'; +import { LegacyConfig } from '../legacy'; export { SavedObjectAttributes, SavedObjectAttribute, @@ -208,13 +208,88 @@ export type MutatingOperationRefreshSetting = boolean | 'wait_for'; */ export type SavedObjectsClientContract = Pick; +/** + * @remarks This is only internal for now, and will only be public when we expose the registerType API + * + * @public + */ +export interface SavedObjectsType { + /** + * The name of the type, which is also used as the internal id. + */ + name: string; + /** + * Is the type hidden by default. If true, repositories will not have access to this type unless explicitly + * declared as an `extraType` when creating the repository. + * + * See {@link SavedObjectsServiceStart.createInternalRepository | createInternalRepository}. + */ + hidden: boolean; + /** + * Is the type global (true), or namespaced (false). + */ + namespaceAgnostic: boolean; + /** + * If defined, the type instances will be stored in the given index instead of the default one. + */ + indexPattern?: string; + /** + * If defined, will be used to convert the type to an alias. + */ + convertToAliasScript?: string; + /** + * The {@link SavedObjectsTypeMappingDefinition | mapping definition} for the type. + */ + mappings: SavedObjectsTypeMappingDefinition; + /** + * An optional map of {@link SavedObjectMigrationFn | migrations} to be used to migrate the type. + */ + migrations?: SavedObjectMigrationMap; +} + /** * @internal * @deprecated */ export interface SavedObjectsLegacyUiExports { - savedObjectMappings: SavedObjectsMapping[]; - savedObjectMigrations: MigrationDefinition; - savedObjectSchemas: SavedObjectsSchemaDefinition; + savedObjectMappings: SavedObjectsLegacyMapping[]; + savedObjectMigrations: SavedObjectsLegacyMigrationDefinitions; + savedObjectSchemas: SavedObjectsLegacySchemaDefinitions; savedObjectValidations: PropertyValidators; } + +/** + * @internal + * @deprecated + */ +export interface SavedObjectsLegacyMapping { + pluginId: string; + properties: SavedObjectsTypeMappingDefinitions; +} + +/** + * @internal + * @deprecated + */ +export interface SavedObjectsLegacyMigrationDefinitions { + [type: string]: SavedObjectMigrationMap; +} + +/** + * @internal + * @deprecated + */ +interface SavedObjectsLegacyTypeSchema { + isNamespaceAgnostic?: boolean; + hidden?: boolean; + indexPattern?: ((config: LegacyConfig) => string) | string; + convertToAliasScript?: string; +} + +/** + * @internal + * @deprecated + */ +export interface SavedObjectsLegacySchemaDefinitions { + [type: string]: SavedObjectsLegacyTypeSchema; +} diff --git a/src/core/server/saved_objects/utils.test.ts b/src/core/server/saved_objects/utils.test.ts new file mode 100644 index 0000000000000..d1c15517e94a6 --- /dev/null +++ b/src/core/server/saved_objects/utils.test.ts @@ -0,0 +1,285 @@ +/* + * 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 { legacyServiceMock } from '../legacy/legacy_service.mock'; +import { convertLegacyTypes, convertTypesToLegacySchema } from './utils'; +import { SavedObjectsLegacyUiExports, SavedObjectsType } from './types'; +import { LegacyConfig } from 'kibana/server'; + +describe('convertLegacyTypes', () => { + let legacyConfig: ReturnType; + + beforeEach(() => { + legacyConfig = legacyServiceMock.createLegacyConfig(); + }); + + it('converts the legacy mappings using default values if no schemas are specified', () => { + const uiExports: SavedObjectsLegacyUiExports = { + savedObjectMappings: [ + { + pluginId: 'pluginA', + properties: { + typeA: { + properties: { + fieldA: { type: 'text' }, + }, + }, + typeB: { + properties: { + fieldB: { type: 'text' }, + }, + }, + }, + }, + { + pluginId: 'pluginB', + properties: { + typeC: { + properties: { + fieldC: { type: 'text' }, + }, + }, + }, + }, + ], + savedObjectMigrations: {}, + savedObjectSchemas: {}, + savedObjectValidations: {}, + }; + + const converted = convertLegacyTypes(uiExports, legacyConfig); + expect(converted).toMatchSnapshot(); + }); + + it('merges the mappings and the schema to create the type when schema exists for the type', () => { + const uiExports: SavedObjectsLegacyUiExports = { + savedObjectMappings: [ + { + pluginId: 'pluginA', + properties: { + typeA: { + properties: { + fieldA: { type: 'text' }, + }, + }, + }, + }, + { + pluginId: 'pluginB', + properties: { + typeC: { + properties: { + fieldC: { type: 'text' }, + }, + }, + }, + }, + ], + savedObjectMigrations: {}, + savedObjectSchemas: { + typeA: { + indexPattern: 'fooBar', + hidden: true, + isNamespaceAgnostic: true, + }, + }, + savedObjectValidations: {}, + }; + + const converted = convertLegacyTypes(uiExports, legacyConfig); + expect(converted).toMatchSnapshot(); + }); + + it('invokes indexPattern to retrieve the index when it is a function', () => { + const indexPatternAccessor: (config: LegacyConfig) => string = jest.fn(config => { + config.get('foo.bar'); + return 'myIndex'; + }); + + const uiExports: SavedObjectsLegacyUiExports = { + savedObjectMappings: [ + { + pluginId: 'pluginA', + properties: { + typeA: { + properties: { + fieldA: { type: 'text' }, + }, + }, + }, + }, + ], + savedObjectMigrations: {}, + savedObjectSchemas: { + typeA: { + indexPattern: indexPatternAccessor, + hidden: true, + isNamespaceAgnostic: true, + }, + }, + savedObjectValidations: {}, + }; + + const converted = convertLegacyTypes(uiExports, legacyConfig); + + expect(indexPatternAccessor).toHaveBeenCalledWith(legacyConfig); + expect(legacyConfig.get).toHaveBeenCalledWith('foo.bar'); + expect(converted.length).toEqual(1); + expect(converted[0].indexPattern).toEqual('myIndex'); + }); + + it('import migrations from the uiExports', () => { + const migrationsA = { + '1.0.0': jest.fn(), + '2.0.4': jest.fn(), + }; + const migrationsB = { + '1.5.3': jest.fn(), + }; + + const uiExports: SavedObjectsLegacyUiExports = { + savedObjectMappings: [ + { + pluginId: 'pluginA', + properties: { + typeA: { + properties: { + fieldA: { type: 'text' }, + }, + }, + }, + }, + { + pluginId: 'pluginB', + properties: { + typeB: { + properties: { + fieldC: { type: 'text' }, + }, + }, + }, + }, + ], + savedObjectMigrations: { + typeA: migrationsA, + typeB: migrationsB, + }, + savedObjectSchemas: {}, + savedObjectValidations: {}, + }; + + const converted = convertLegacyTypes(uiExports, legacyConfig); + expect(converted.length).toEqual(2); + expect(converted[0].migrations).toEqual(migrationsA); + expect(converted[1].migrations).toEqual(migrationsB); + }); + + it('merges everything when all are present', () => { + const uiExports: SavedObjectsLegacyUiExports = { + savedObjectMappings: [ + { + pluginId: 'pluginA', + properties: { + typeA: { + properties: { + fieldA: { type: 'text' }, + }, + }, + typeB: { + properties: { + fieldB: { type: 'text' }, + anotherFieldB: { type: 'boolean' }, + }, + }, + }, + }, + { + pluginId: 'pluginB', + properties: { + typeC: { + properties: { + fieldC: { type: 'text' }, + }, + }, + }, + }, + ], + savedObjectMigrations: { + typeA: { + '1.0.0': jest.fn(), + '2.0.4': jest.fn(), + }, + typeC: { + '1.5.3': jest.fn(), + }, + }, + savedObjectSchemas: { + typeA: { + indexPattern: jest.fn(config => { + config.get('foo.bar'); + return 'myIndex'; + }), + hidden: true, + isNamespaceAgnostic: true, + }, + typeB: { + convertToAliasScript: 'some alias script', + hidden: false, + }, + }, + savedObjectValidations: {}, + }; + + const converted = convertLegacyTypes(uiExports, legacyConfig); + expect(converted).toMatchSnapshot(); + }); +}); + +describe('convertTypesToLegacySchema', () => { + it('converts types to the legacy schema format', () => { + const types: SavedObjectsType[] = [ + { + name: 'typeA', + hidden: false, + namespaceAgnostic: true, + mappings: { properties: {} }, + convertToAliasScript: 'some script', + }, + { + name: 'typeB', + hidden: true, + namespaceAgnostic: false, + indexPattern: 'myIndex', + mappings: { properties: {} }, + }, + ]; + expect(convertTypesToLegacySchema(types)).toEqual({ + typeA: { + hidden: false, + isNamespaceAgnostic: true, + convertToAliasScript: 'some script', + }, + typeB: { + hidden: true, + isNamespaceAgnostic: false, + indexPattern: 'myIndex', + }, + }); + }); +}); diff --git a/src/core/server/saved_objects/utils.ts b/src/core/server/saved_objects/utils.ts new file mode 100644 index 0000000000000..5c4d0ccb84b25 --- /dev/null +++ b/src/core/server/saved_objects/utils.ts @@ -0,0 +1,76 @@ +/* + * 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 { LegacyConfig } from '../legacy'; +import { SavedObjectsType, SavedObjectsLegacyUiExports } from './types'; +import { SavedObjectsSchemaDefinition } from './schema'; + +/** + * Converts the legacy savedObjects mappings, schema, and migrations + * to actual {@link SavedObjectsType | saved object types} + */ +export const convertLegacyTypes = ( + { + savedObjectMappings = [], + savedObjectMigrations = {}, + savedObjectSchemas = {}, + }: SavedObjectsLegacyUiExports, + legacyConfig: LegacyConfig +): SavedObjectsType[] => { + return savedObjectMappings.reduce((types, { pluginId, properties }) => { + return [ + ...types, + ...Object.entries(properties).map(([type, mappings]) => { + const schema = savedObjectSchemas[type]; + const migrations = savedObjectMigrations[type]; + return { + name: type, + hidden: schema?.hidden ?? false, + namespaceAgnostic: schema?.isNamespaceAgnostic ?? false, + mappings, + indexPattern: + typeof schema?.indexPattern === 'function' + ? schema.indexPattern(legacyConfig) + : schema?.indexPattern, + convertToAliasScript: schema?.convertToAliasScript, + migrations: migrations ?? {}, + }; + }), + ]; + }, [] as SavedObjectsType[]); +}; + +/** + * Convert {@link SavedObjectsType | saved object types} to the legacy {@link SavedObjectsSchemaDefinition | schema} format + */ +export const convertTypesToLegacySchema = ( + types: SavedObjectsType[] +): SavedObjectsSchemaDefinition => { + return types.reduce((schema, type) => { + return { + ...schema, + [type.name]: { + isNamespaceAgnostic: type.namespaceAgnostic, + hidden: type.hidden, + indexPattern: type.indexPattern, + convertToAliasScript: type.convertToAliasScript, + }, + }; + }, {} as SavedObjectsSchemaDefinition); +}; diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index fb27fcccc2abe..cf8fafd7ea7c4 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1102,6 +1102,8 @@ export interface LogRecord { [name: string]: any; }; // (undocumented) + pid: number; + // (undocumented) timestamp: Date; } @@ -1421,6 +1423,19 @@ export interface SavedObjectAttributes { // @public export type SavedObjectAttributeSingle = string | number | boolean | null | undefined | SavedObjectAttributes; +// Warning: (ae-forgotten-export) The symbol "SavedObjectUnsanitizedDoc" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "SavedObjectMigrationFn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "SavedObjectUnsanitizedDoc" +// +// @public +export type SavedObjectMigrationFn = (doc: SavedObjectUnsanitizedDoc, log: SavedObjectsMigrationLogger) => SavedObjectUnsanitizedDoc; + +// @public +export interface SavedObjectMigrationMap { + // (undocumented) + [version: string]: SavedObjectMigrationFn; +} + // @public export interface SavedObjectReference { // (undocumented) @@ -1431,6 +1446,12 @@ export interface SavedObjectReference { type: string; } +// Warning: (ae-forgotten-export) The symbol "SavedObjectDoc" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "Referencable" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export type SavedObjectSanitizedDoc = SavedObjectDoc & Referencable; + // @public (undocumented) export interface SavedObjectsBaseOptions { namespace?: string; @@ -1534,6 +1555,32 @@ export interface SavedObjectsClientWrapperOptions { request: KibanaRequest; } +// @public +export interface SavedObjectsComplexFieldMapping { + // (undocumented) + dynamic?: string; + // (undocumented) + properties: SavedObjectsMappingProperties; + // (undocumented) + type?: string; +} + +// @public +export interface SavedObjectsCoreFieldMapping { + // (undocumented) + enabled?: boolean; + // (undocumented) + fields?: { + [subfield: string]: { + type: string; + }; + }; + // (undocumented) + index?: boolean; + // (undocumented) + type: string; +} + // @public (undocumented) export interface SavedObjectsCreateOptions extends SavedObjectsBaseOptions { id?: string; @@ -1629,6 +1676,9 @@ export interface SavedObjectsExportResultDetails { }>; } +// @public +export type SavedObjectsFieldMapping = SavedObjectsCoreFieldMapping | SavedObjectsComplexFieldMapping; + // @public (undocumented) export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions { // (undocumented) @@ -1793,6 +1843,12 @@ export interface SavedObjectsLegacyService { types: string[]; } +// @public +export interface SavedObjectsMappingProperties { + // (undocumented) + [field: string]: SavedObjectsFieldMapping; +} + // @public (undocumented) export interface SavedObjectsMigrationLogger { // (undocumented) @@ -1800,6 +1856,8 @@ export interface SavedObjectsMigrationLogger { // (undocumented) info: (msg: string) => void; // (undocumented) + warn: (msg: string) => void; + // @deprecated (undocumented) warning: (msg: string) => void; } @@ -1809,8 +1867,6 @@ export interface SavedObjectsMigrationVersion { [pluginName: string]: string; } -// Warning: (ae-missing-release-tag) "RawDoc" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public export interface SavedObjectsRawDoc { // (undocumented) @@ -1819,8 +1875,10 @@ export interface SavedObjectsRawDoc { _primary_term?: number; // (undocumented) _seq_no?: number; + // Warning: (ae-forgotten-export) The symbol "SavedObjectsRawDocSource" needs to be exported by the entry point index.d.ts + // // (undocumented) - _source: any; + _source: SavedObjectsRawDocSource; // (undocumented) _type?: string; } @@ -1834,7 +1892,7 @@ export class SavedObjectsRepository { // Warning: (ae-forgotten-export) The symbol "KibanaMigrator" needs to be exported by the entry point index.d.ts // // @internal - static createRepository(migrator: KibanaMigrator, schema: SavedObjectsSchema, config: LegacyConfig, indexName: string, callCluster: APICaller, extraTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository; + static createRepository(migrator: KibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, callCluster: APICaller, extraTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository; delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>; deleteByNamespace(namespace: string, options?: SavedObjectsDeleteByNamespaceOptions): Promise; // (undocumented) @@ -1873,7 +1931,7 @@ export interface SavedObjectsResolveImportErrorsOptions { supportedTypes: string[]; } -// @internal (undocumented) +// @internal @deprecated (undocumented) export class SavedObjectsSchema { // Warning: (ae-forgotten-export) The symbol "SavedObjectsSchemaDefinition" needs to be exported by the entry point index.d.ts constructor(schemaDefinition?: SavedObjectsSchemaDefinition); @@ -1887,14 +1945,16 @@ export class SavedObjectsSchema { isNamespaceAgnostic(type: string): boolean; } -// @internal (undocumented) +// @public export class SavedObjectsSerializer { - constructor(schema: SavedObjectsSchema); + // Warning: (ae-forgotten-export) The symbol "ISavedObjectTypeRegistry" needs to be exported by the entry point index.d.ts + // + // @internal + constructor(registry: ISavedObjectTypeRegistry); generateRawId(namespace: string | undefined, type: string, id?: string): string; - isRawSavedObject(rawDoc: SavedObjectsRawDoc): any; - // Warning: (ae-forgotten-export) The symbol "SanitizedSavedObjectDoc" needs to be exported by the entry point index.d.ts - rawToSavedObject(doc: SavedObjectsRawDoc): SanitizedSavedObjectDoc; - savedObjectToRaw(savedObj: SanitizedSavedObjectDoc): SavedObjectsRawDoc; + isRawSavedObject(rawDoc: SavedObjectsRawDoc): boolean; + rawToSavedObject(doc: SavedObjectsRawDoc): SavedObjectSanitizedDoc; + savedObjectToRaw(savedObj: SavedObjectSanitizedDoc): SavedObjectsRawDoc; } // @public @@ -1907,9 +1967,27 @@ export interface SavedObjectsServiceSetup { export interface SavedObjectsServiceStart { createInternalRepository: (extraTypes?: string[]) => ISavedObjectsRepository; createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository; + createSerializer: () => SavedObjectsSerializer; getScopedClient: (req: KibanaRequest, options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract; } +// @public (undocumented) +export interface SavedObjectsType { + convertToAliasScript?: string; + hidden: boolean; + indexPattern?: string; + mappings: SavedObjectsTypeMappingDefinition; + migrations?: SavedObjectMigrationMap; + name: string; + namespaceAgnostic: boolean; +} + +// @public +export interface SavedObjectsTypeMappingDefinition { + // (undocumented) + properties: SavedObjectsMappingProperties; +} + // @public (undocumented) export interface SavedObjectsUpdateOptions extends SavedObjectsBaseOptions { references?: SavedObjectReference[]; @@ -1925,6 +2003,16 @@ export interface SavedObjectsUpdateResponse = { + const configKeys: Record = { 'xpack.task_manager.index': '.kibana_task_manager', }; + const config = { get: (path: string) => configKeys[path] }; + + const savedObjectTypes = convertLegacyTypes(uiExports, config as LegacyConfig); + const typeRegistry = new SavedObjectTypeRegistry(); + savedObjectTypes.forEach(type => typeRegistry.registerType(type)); const logger = { trace: log.verbose.bind(log), @@ -117,7 +124,6 @@ export async function migrateKibanaIndex({ }; const migratorOptions = { - config: { get: (path: string) => config[path] } as any, savedObjectsConfig: { scrollDuration: '5m', batchSize: 100, @@ -129,9 +135,7 @@ export async function migrateKibanaIndex({ } as any, logger, kibanaVersion, - savedObjectSchemas: new SavedObjectsSchema(uiExports.savedObjectSchemas), - savedObjectMappings: uiExports.savedObjectMappings, - savedObjectMigrations: uiExports.savedObjectMigrations, + typeRegistry, savedObjectValidations: uiExports.savedObjectValidations, callCluster: (path: string, ...args: any[]) => (get(client, path) as Function).call(client, ...args), diff --git a/src/legacy/core_plugins/console_legacy/public/styles/_app.scss b/src/legacy/core_plugins/console_legacy/public/styles/_app.scss index 3b6297f9cdbff..865a4fc7fafb0 100644 --- a/src/legacy/core_plugins/console_legacy/public/styles/_app.scss +++ b/src/legacy/core_plugins/console_legacy/public/styles/_app.scss @@ -48,6 +48,7 @@ button { line-height: inherit; } + position: absolute; z-index: $euiZLevel1; top: 0; @@ -89,3 +90,12 @@ .conApp__settingsModal { min-width: 460px; } + +.conApp__requestProgressBarContainer { + position: relative; + z-index: $euiZLevel2; +} + +.conApp__tabsExtension { + border-bottom: $euiBorderThin; +} diff --git a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js index a6fe58503cd02..743f6caee4edd 100644 --- a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js +++ b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js @@ -21,7 +21,7 @@ import _ from 'lodash'; import moment from 'moment'; import expect from '@kbn/expect'; -jest.mock('../../../../../ui/public/agg_types/agg_configs', () => ({ +jest.mock('../../search/aggs', () => ({ AggConfigs: function AggConfigs() { return { createAggConfig: ({ params }) => ({ diff --git a/src/legacy/core_plugins/data/public/actions/select_range_action.ts b/src/legacy/core_plugins/data/public/actions/select_range_action.ts index 4ea5c78a9fd2b..7e1135ca96f9e 100644 --- a/src/legacy/core_plugins/data/public/actions/select_range_action.ts +++ b/src/legacy/core_plugins/data/public/actions/select_range_action.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { - IAction, + Action, createAction, IncompatibleActionError, } from '../../../../../plugins/ui_actions/public'; @@ -55,7 +55,7 @@ async function isCompatible(context: ActionContext) { export function selectRangeAction( filterManager: FilterManager, timeFilter: TimefilterContract -): IAction { +): Action { return createAction({ type: SELECT_RANGE_ACTION, id: SELECT_RANGE_ACTION, diff --git a/src/legacy/core_plugins/data/public/actions/value_click_action.ts b/src/legacy/core_plugins/data/public/actions/value_click_action.ts index 2f622eb1eb669..1e474b8f9355c 100644 --- a/src/legacy/core_plugins/data/public/actions/value_click_action.ts +++ b/src/legacy/core_plugins/data/public/actions/value_click_action.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { toMountPoint } from '../../../../../plugins/kibana_react/public'; import { - IAction, + Action, createAction, IncompatibleActionError, } from '../../../../../plugins/ui_actions/public'; @@ -58,7 +58,7 @@ async function isCompatible(context: ActionContext) { export function valueClickAction( filterManager: FilterManager, timeFilter: TimefilterContract -): IAction { +): Action { return createAction({ type: VALUE_CLICK_ACTION, id: VALUE_CLICK_ACTION, diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index 7fe487667f94e..50120292a627a 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -18,7 +18,7 @@ */ // /// Define plugin function -import { DataPlugin as Plugin, DataStart } from './plugin'; +import { DataPlugin as Plugin } from './plugin'; export function plugin() { return new Plugin(); @@ -27,14 +27,58 @@ export function plugin() { // /// Export types & static code /** @public types */ -export { DataStart }; +export { DataSetup, DataStart } from './plugin'; export { SavedQueryAttributes, SavedQuery, SavedQueryTimeFilter, } from '../../../../plugins/data/public'; +export { + // agg_types + AggParam, + AggParamOption, + DateRangeKey, + IAggConfig, + IAggConfigs, + IAggType, + IFieldParamType, + IMetricAggType, + IpRangeKey, + ISchemas, + OptionedParamEditorProps, + OptionedValueProp, +} from './search/types'; /** @public static code */ export * from '../common'; export { FilterStateManager } from './filter/filter_manager'; -export { getRequestInspectorStats, getResponseInspectorStats } from './search'; +export { + // agg_types TODO need to group these under a namespace or prefix + AggParamType, + AggTypeFilters, // TODO convert to interface + aggTypeFilters, + AggTypeFieldFilters, // TODO convert to interface + AggGroupNames, + aggGroupNamesMap, + BUCKET_TYPES, + CidrMask, + convertDateRangeToString, + convertIPRangeToString, + intervalOptions, // only used in Discover + isDateHistogramBucketAggConfig, + isStringType, + isType, + isValidInterval, + isValidJson, + METRIC_TYPES, + OptionedParamType, + parentPipelineType, + propFilter, + Schema, + Schemas, + siblingPipelineType, + termsAggFilter, + // search_source + getRequestInspectorStats, + getResponseInspectorStats, +} from './search'; diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index da35366cdff31..e13e8e34eaebe 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -43,17 +43,28 @@ import { VALUE_CLICK_TRIGGER, // eslint-disable-next-line @kbn/eslint/no-restricted-paths } from '../../../../plugins/embeddable/public/lib/triggers'; -import { IUiActionsSetup, IUiActionsStart } from '../../../../plugins/ui_actions/public'; +import { UiActionsSetup, UiActionsStart } from '../../../../plugins/ui_actions/public'; + +import { SearchSetup, SearchStart, SearchService } from './search/search_service'; export interface DataPluginSetupDependencies { data: DataPublicPluginSetup; expressions: ExpressionsSetup; - uiActions: IUiActionsSetup; + uiActions: UiActionsSetup; } export interface DataPluginStartDependencies { data: DataPublicPluginStart; - uiActions: IUiActionsStart; + uiActions: UiActionsStart; +} + +/** + * Interface for this plugin's returned `setup` contract. + * + * @public + */ +export interface DataSetup { + search: SearchSetup; } /** @@ -61,7 +72,9 @@ export interface DataPluginStartDependencies { * * @public */ -export interface DataStart {} // eslint-disable-line @typescript-eslint/no-empty-interface +export interface DataStart { + search: SearchStart; +} /** * Data Plugin - public @@ -76,7 +89,10 @@ export interface DataStart {} // eslint-disable-line @typescript-eslint/no-empty */ export class DataPlugin - implements Plugin { + implements + Plugin { + private readonly search = new SearchService(); + public setup(core: CoreSetup, { data, uiActions }: DataPluginSetupDependencies) { setInjectedMetadata(core.injectedMetadata); @@ -89,6 +105,10 @@ export class DataPlugin uiActions.registerAction( valueClickAction(data.query.filterManager, data.query.timefilter.timefilter) ); + + return { + search: this.search.setup(core), + }; } public start(core: CoreStart, { data, uiActions }: DataPluginStartDependencies): DataStart { @@ -102,7 +122,9 @@ export class DataPlugin uiActions.attachAction(SELECT_RANGE_TRIGGER, SELECT_RANGE_ACTION); uiActions.attachAction(VALUE_CLICK_TRIGGER, VALUE_CLICK_ACTION); - return {}; + return { + search: this.search.start(core), + }; } public stop() {} diff --git a/src/legacy/ui/public/agg_types/__tests__/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js similarity index 99% rename from src/legacy/ui/public/agg_types/__tests__/buckets/_terms_other_bucket_helper.js rename to src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js index acf932c1fb451..247290731df57 100644 --- a/src/legacy/ui/public/agg_types/__tests__/buckets/_terms_other_bucket_helper.js +++ b/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js @@ -24,7 +24,7 @@ import { mergeOtherBucketAggResponse, updateMissingBucket, } from '../../buckets/_terms_other_bucket_helper'; -import { Vis } from '../../../../../core_plugins/visualizations/public'; +import { Vis } from '../../../../../../../core_plugins/visualizations/public'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; const visConfigSingleTerm = { diff --git a/src/legacy/ui/public/agg_types/agg_config.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts similarity index 92% rename from src/legacy/ui/public/agg_types/agg_config.ts rename to src/legacy/core_plugins/data/public/search/aggs/agg_config.ts index 17a8b14b57d02..ba7faf8c34b59 100644 --- a/src/legacy/ui/public/agg_types/agg_config.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts @@ -27,17 +27,17 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; -import { AggType } from './agg_type'; +import { IAggType } from './agg_type'; import { AggGroupNames } from './agg_groups'; import { writeParams } from './agg_params'; -import { AggConfigs } from './agg_configs'; +import { IAggConfigs } from './agg_configs'; import { Schema } from './schemas'; import { ISearchSource, FetchOptions, fieldFormats, KBN_FIELD_TYPES, -} from '../../../../plugins/data/public'; +} from '../../../../../../plugins/data/public'; export interface AggConfigOptions { enabled: boolean; @@ -58,15 +58,20 @@ const unknownSchema: Schema = { defaults: {}, editor: false, group: AggGroupNames.Metrics, + aggSettings: { + top_hits: { + allowStrings: true, + }, + }, }; -const getTypeFromRegistry = (type: string): AggType => { +const getTypeFromRegistry = (type: string): IAggType => { // We need to inline require here, since we're having a cyclic dependency // from somewhere inside agg_types back to AggConfig. - const aggTypes = require('./agg_types').aggTypes; + const aggTypes = require('../aggs').aggTypes; const registeredType = - aggTypes.metrics.find((agg: AggType) => agg.name === type) || - aggTypes.buckets.find((agg: AggType) => agg.name === type); + aggTypes.metrics.find((agg: IAggType) => agg.name === type) || + aggTypes.buckets.find((agg: IAggType) => agg.name === type); if (!registeredType) { throw new Error('unknown type'); @@ -85,6 +90,9 @@ const getSchemaFromRegistry = (schemas: any, schema: string): Schema => { return registeredSchema; }; +// TODO need to make a more explicit interface for this +export type IAggConfig = AggConfig; + export class AggConfig { /** * Ensure that all of the objects in the list have ids, the objects @@ -122,19 +130,19 @@ export class AggConfig { ); } - public aggConfigs: AggConfigs; + public aggConfigs: IAggConfigs; public id: string; public enabled: boolean; public params: any; - public parent?: AggConfigs; + public parent?: IAggConfigs; public brandNew?: boolean; private __schema: Schema; - private __type: AggType; + private __type: IAggType; private __typeDecorations: any; private subAggs: AggConfig[] = []; - constructor(aggConfigs: AggConfigs, opts: AggConfigOptions) { + constructor(aggConfigs: IAggConfigs, opts: AggConfigOptions) { this.aggConfigs = aggConfigs; this.id = String(opts.id || AggConfig.nextId(aggConfigs.aggs as any)); this.enabled = typeof opts.enabled === 'boolean' ? opts.enabled : true; @@ -207,7 +215,7 @@ export class AggConfig { return _.get(this.params, key); } - write(aggs?: AggConfigs) { + write(aggs?: IAggConfigs) { return writeParams(this.type.params, this, aggs); } @@ -262,7 +270,7 @@ export class AggConfig { * @return {void|Object} - if the config has a dsl representation, it is * returned, else undefined is returned */ - toDsl(aggConfigs?: AggConfigs) { + toDsl(aggConfigs?: IAggConfigs) { if (this.type.hasNoDsl) return; const output = this.write(aggConfigs) as any; @@ -360,7 +368,7 @@ export class AggConfig { if (!this.type) return ''; return percentageMode - ? i18n.translate('common.ui.vis.aggConfig.percentageOfLabel', { + ? i18n.translate('data.search.aggs.percentageOfLabel', { defaultMessage: 'Percentage of {label}', values: { label: this.type.makeLabel(this) }, }) @@ -435,7 +443,7 @@ export class AggConfig { if (fieldParam) { // @ts-ignore - availableFields = fieldParam.getAvailableFields(this.getIndexPattern().fields); + availableFields = fieldParam.getAvailableFields(this); } // clear out the previous params except for a few special ones @@ -448,7 +456,7 @@ export class AggConfig { }); } - public setType(type: string | AggType) { + public setType(type: string | IAggType) { this.type = typeof type === 'string' ? getTypeFromRegistry(type) : type; } diff --git a/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts similarity index 98% rename from src/legacy/ui/public/agg_types/agg_configs.ts rename to src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts index 47e2222abe1e8..7e7e4944b00da 100644 --- a/src/legacy/ui/public/agg_types/agg_configs.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts @@ -35,7 +35,7 @@ import { ISearchSource, FetchOptions, TimeRange, -} from '../../../../plugins/data/public'; +} from '../../../../../../plugins/data/public'; type Schemas = Record; @@ -55,6 +55,9 @@ function parseParentAggs(dslLvlCursor: any, dsl: any) { } } +// TODO need to make a more explicit interface for this +export type IAggConfigs = AggConfigs; + export class AggConfigs { public indexPattern: IndexPattern; public schemas: any; diff --git a/src/legacy/ui/public/agg_types/agg_groups.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts similarity index 87% rename from src/legacy/ui/public/agg_types/agg_groups.ts rename to src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts index d08e875bf213e..d21f5c8968840 100644 --- a/src/legacy/ui/public/agg_types/agg_groups.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts @@ -28,10 +28,10 @@ export const AggGroupNames = Object.freeze({ export type AggGroupNames = $Values; export const aggGroupNamesMap = () => ({ - [AggGroupNames.Metrics]: i18n.translate('common.ui.aggTypes.aggGroups.metricsText', { + [AggGroupNames.Metrics]: i18n.translate('data.search.aggs.aggGroups.metricsText', { defaultMessage: 'Metrics', }), - [AggGroupNames.Buckets]: i18n.translate('common.ui.aggTypes.aggGroups.bucketsText', { + [AggGroupNames.Buckets]: i18n.translate('data.search.aggs.aggGroups.bucketsText', { defaultMessage: 'Buckets', }), }); diff --git a/src/legacy/ui/public/agg_types/agg_params.test.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/agg_params.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts index 25e62e06d52d7..30ab272537dad 100644 --- a/src/legacy/ui/public/agg_types/agg_params.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts @@ -21,7 +21,7 @@ import { initParams } from './agg_params'; import { BaseParamType } from './param_types/base'; import { FieldParamType } from './param_types/field'; import { OptionedParamType } from './param_types/optioned'; -import { AggParamType } from '../agg_types/param_types/agg'; +import { AggParamType } from '../aggs/param_types/agg'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/agg_params.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts similarity index 97% rename from src/legacy/ui/public/agg_types/agg_params.ts rename to src/legacy/core_plugins/data/public/search/aggs/agg_params.ts index 262a57f4a5aa3..34727ff4614b9 100644 --- a/src/legacy/ui/public/agg_types/agg_params.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts @@ -25,7 +25,7 @@ import { JsonParamType } from './param_types/json'; import { BaseParamType } from './param_types/base'; import { AggConfig } from './agg_config'; -import { AggConfigs } from './agg_configs'; +import { IAggConfigs } from './agg_configs'; const paramTypeMap = { field: FieldParamType, @@ -73,7 +73,7 @@ export const writeParams = < >( params: Array> = [], aggConfig: TAggConfig, - aggs?: AggConfigs, + aggs?: IAggConfigs, locals?: Record ) => { const output = { params: {} as Record }; diff --git a/src/legacy/ui/public/agg_types/agg_type.test.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts similarity index 94% rename from src/legacy/ui/public/agg_types/agg_type.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts index 9b34910e81e88..6d4c2d1317f50 100644 --- a/src/legacy/ui/public/agg_types/agg_type.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts @@ -18,7 +18,7 @@ */ import { AggType, AggTypeConfig } from './agg_type'; -import { AggConfig } from './agg_config'; +import { IAggConfig } from './agg_config'; import { npStart } from 'ui/new_platform'; jest.mock('ui/new_platform'); @@ -48,7 +48,7 @@ describe('AggType Class', () => { describe('makeLabel', () => { it('makes a function when the makeLabel config is not specified', () => { const makeLabel = () => 'label'; - const aggConfig = {} as AggConfig; + const aggConfig = {} as IAggConfig; const config: AggTypeConfig = { name: 'name', title: 'title', @@ -64,7 +64,7 @@ describe('AggType Class', () => { describe('getResponseAggs/getRequestAggs', () => { it('copies the value', () => { - const testConfig = (aggConfig: AggConfig) => [aggConfig]; + const testConfig = (aggConfig: IAggConfig) => [aggConfig]; const aggType = new AggType({ name: 'name', @@ -78,7 +78,7 @@ describe('AggType Class', () => { }); it('defaults to noop', () => { - const aggConfig = {} as AggConfig; + const aggConfig = {} as IAggConfig; const aggType = new AggType({ name: 'name', title: 'title', @@ -130,13 +130,13 @@ describe('AggType Class', () => { }); describe('getFormat', function() { - let aggConfig: AggConfig; + let aggConfig: IAggConfig; let field: any; beforeEach(() => { aggConfig = ({ getField: jest.fn(() => field), - } as unknown) as AggConfig; + } as unknown) as IAggConfig; }); it('returns the formatter for the aggConfig', () => { diff --git a/src/legacy/ui/public/agg_types/agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts similarity index 94% rename from src/legacy/ui/public/agg_types/agg_type.ts rename to src/legacy/core_plugins/data/public/search/aggs/agg_type.ts index 7ec688277b9c4..56299839d0a6d 100644 --- a/src/legacy/ui/public/agg_types/agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts @@ -23,11 +23,15 @@ import { npStart } from 'ui/new_platform'; import { initParams } from './agg_params'; import { AggConfig } from './agg_config'; -import { AggConfigs } from './agg_configs'; -import { Adapters } from '../../../../plugins/inspector/public'; +import { IAggConfigs } from './agg_configs'; +import { Adapters } from '../../../../../../plugins/inspector/public'; import { BaseParamType } from './param_types/base'; -import { AggParamType } from '../agg_types/param_types/agg'; -import { KBN_FIELD_TYPES, fieldFormats, ISearchSource } from '../../../../plugins/data/public'; +import { AggParamType } from './param_types/agg'; +import { + KBN_FIELD_TYPES, + fieldFormats, + ISearchSource, +} from '../../../../../../plugins/data/public'; export interface AggTypeConfig< TAggConfig extends AggConfig = AggConfig, @@ -48,7 +52,7 @@ export interface AggTypeConfig< decorateAggConfig?: () => any; postFlightRequest?: ( resp: any, - aggConfigs: AggConfigs, + aggConfigs: IAggConfigs, aggConfig: TAggConfig, searchSource: ISearchSource, inspectorAdapters: Adapters, @@ -66,6 +70,9 @@ const getFormat = (agg: AggConfig) => { return field ? field.format : fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.STRING); }; +// TODO need to make a more explicit interface for this +export type IAggType = AggType; + export class AggType< TAggConfig extends AggConfig = AggConfig, TParam extends AggParamType = AggParamType @@ -178,7 +185,7 @@ export class AggType< */ postFlightRequest: ( resp: any, - aggConfigs: AggConfigs, + aggConfigs: IAggConfigs, aggConfig: TAggConfig, searchSource: ISearchSource, inspectorAdapters: Adapters, @@ -239,7 +246,7 @@ export class AggType< if (config.customLabels !== false) { params.push({ name: 'customLabel', - displayName: i18n.translate('common.ui.aggTypes.string.customLabel', { + displayName: i18n.translate('data.search.aggs.string.customLabel', { defaultMessage: 'Custom label', }), type: 'string', diff --git a/src/legacy/ui/public/agg_types/agg_types.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_types.ts similarity index 73% rename from src/legacy/ui/public/agg_types/agg_types.ts rename to src/legacy/core_plugins/data/public/search/aggs/agg_types.ts index 1b05f5926ebfc..c16eb06eeb116 100644 --- a/src/legacy/ui/public/agg_types/agg_types.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_types.ts @@ -50,8 +50,6 @@ import { bucketAvgMetricAgg } from './metrics/bucket_avg'; import { bucketMinMetricAgg } from './metrics/bucket_min'; import { bucketMaxMetricAgg } from './metrics/bucket_max'; -export { AggType } from './agg_type'; - export const aggTypes = { metrics: [ countMetricAgg, @@ -90,3 +88,27 @@ export const aggTypes = { geoTileBucketAgg, ], }; + +export { AggType } from './agg_type'; +export { AggConfig } from './agg_config'; +export { AggConfigs } from './agg_configs'; +export { FieldParamType } from './param_types'; +export { aggTypeFieldFilters } from './param_types/filter'; +export { parentPipelineAggHelper } from './metrics/lib/parent_pipeline_agg_helper'; + +// static code +export { AggParamType } from './param_types/agg'; +export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; +export { intervalOptions } from './buckets/_interval_options'; // only used in Discover +export { isDateHistogramBucketAggConfig, setBounds } from './buckets/date_histogram'; +export { termsAggFilter } from './buckets/terms'; +export { isType, isStringType } from './buckets/migrate_include_exclude_format'; +export { CidrMask } from './buckets/lib/cidr_mask'; +export { convertDateRangeToString } from './buckets/date_range'; +export { convertIPRangeToString } from './buckets/ip_range'; +export { aggTypeFilters, propFilter } from './filter'; +export { OptionedParamType } from './param_types/optioned'; +export { isValidJson, isValidInterval } from './utils'; +export { BUCKET_TYPES } from './buckets/bucket_agg_types'; +export { METRIC_TYPES } from './metrics/metric_agg_types'; +export { ISchemas, Schema, Schemas } from './schemas'; diff --git a/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts similarity index 96% rename from src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts index 9b7c97a8f11b6..546d054c5af97 100644 --- a/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts @@ -18,7 +18,7 @@ */ import { AggConfig } from '../agg_config'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; diff --git a/src/legacy/ui/public/agg_types/buckets/_interval_options.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts similarity index 66% rename from src/legacy/ui/public/agg_types/buckets/_interval_options.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts index 01d0abb7a366c..e196687607d19 100644 --- a/src/legacy/ui/public/agg_types/buckets/_interval_options.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts @@ -21,7 +21,7 @@ import { IBucketAggConfig } from './_bucket_agg_type'; export const intervalOptions = [ { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.autoDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.autoDisplayName', { defaultMessage: 'Auto', }), val: 'auto', @@ -32,49 +32,49 @@ export const intervalOptions = [ }, }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.millisecondDisplayName', { defaultMessage: 'Millisecond', }), val: 'ms', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.secondDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.secondDisplayName', { defaultMessage: 'Second', }), val: 's', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.minuteDisplayName', { defaultMessage: 'Minute', }), val: 'm', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.hourlyDisplayName', { defaultMessage: 'Hourly', }), val: 'h', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.dailyDisplayName', { defaultMessage: 'Daily', }), val: 'd', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.weeklyDisplayName', { defaultMessage: 'Weekly', }), val: 'w', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.monthlyDisplayName', { defaultMessage: 'Monthly', }), val: 'M', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.yearlyDisplayName', { defaultMessage: 'Yearly', }), val: 'y', diff --git a/src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js similarity index 99% rename from src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js rename to src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js index c8580183756f4..ddab360161744 100644 --- a/src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import { esFilters, esQuery } from '../../../../../plugins/data/public'; +import { esFilters, esQuery } from '../../../../../../../plugins/data/public'; import { AggGroupNames } from '../agg_groups'; /** diff --git a/src/legacy/ui/public/agg_types/buckets/bucket_agg_types.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/bucket_agg_types.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/bucket_agg_types.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/bucket_agg_types.ts diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts similarity index 98% rename from src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts index 9426df7d34c29..e212132257ef6 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts @@ -23,7 +23,7 @@ import { intervalOptions } from '../_interval_options'; import { AggConfigs } from '../../agg_configs'; import { IBucketDateHistogramAggConfig } from '../date_histogram'; import { BUCKET_TYPES } from '../bucket_agg_types'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts index f91a92eab1c33..e634b5daf0ac3 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts @@ -19,7 +19,7 @@ import moment from 'moment'; import { IBucketDateHistogramAggConfig } from '../date_histogram'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterDateHistogram = ( agg: IBucketDateHistogramAggConfig, diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts index 9c2c4f72704f4..e224253a6e314 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts @@ -19,7 +19,7 @@ import moment from 'moment'; import { createFilterDateRange } from './date_range'; -import { fieldFormats } from '../../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts index 01689d954a072..f7f2cfdb7bb61 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts @@ -20,7 +20,7 @@ import moment from 'moment'; import { IBucketAggConfig } from '../_bucket_agg_type'; import { DateRangeKey } from '../date_range'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterDateRange = (agg: IBucketAggConfig, { from, to }: DateRangeKey) => { const filter: esFilters.RangeFilterParams = {}; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts index 6b614514580b6..715f6895374e6 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts @@ -19,7 +19,7 @@ import { get } from 'lodash'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => { // have the aggConfig write agg dsl params diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts index ef49636f9e0c1..1a78967261fa6 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts @@ -20,7 +20,7 @@ import { createFilterHistogram } from './histogram'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { fieldFormats } from '../../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts index fc587fa9ecdb6..820f3de5ae9f0 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => { const value = parseInt(key, 10); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts index a9eca3bbb7a56..e92ba5cb2852a 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts @@ -19,7 +19,7 @@ import { createFilterIpRange } from './ip_range'; import { AggConfigs } from '../../agg_configs'; -import { fieldFormats } from '../../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts similarity index 95% rename from src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts index a513b8c782739..d78f4579cd713 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts @@ -20,7 +20,7 @@ import { CidrMask } from '../lib/cidr_mask'; import { IBucketAggConfig } from '../_bucket_agg_type'; import { IpRangeKey } from '../ip_range'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey) => { let range: esFilters.RangeFilterParams; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts index 720e952c28821..2f74f23721813 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts @@ -18,7 +18,7 @@ */ import { createFilterRange } from './range'; -import { fieldFormats } from '../../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts similarity index 93% rename from src/legacy/ui/public/agg_types/buckets/create_filter/range.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts index 929827c6e3fec..125a30a1ab1dd 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => { return esFilters.buildRangeFilter( diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts similarity index 98% rename from src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts index 86c0aa24f529a..d5fd1337f2cb2 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts @@ -21,7 +21,7 @@ import { createFilterTerms } from './terms'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts similarity index 95% rename from src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts index 5bd770e672786..e0d1f91c1e16a 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, params: any) => { const field = aggConfig.params.field; diff --git a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts similarity index 95% rename from src/legacy/ui/public/agg_types/buckets/date_histogram.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts index 33672b54b1f2e..dc0f9baa6d0cc 100644 --- a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts @@ -22,19 +22,17 @@ import moment from 'moment-timezone'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; +import { timefilter } from 'ui/timefilter'; +import { TimeBuckets } from 'ui/time_buckets'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterDateHistogram } from './create_filter/date_histogram'; import { intervalOptions } from './_interval_options'; -import { timefilter } from '../../timefilter'; -import { dateHistogramInterval } from '../../../../core_plugins/data/public'; +import { dateHistogramInterval } from '../../../../common'; import { writeParams } from '../agg_params'; import { isMetricAggType } from '../metrics/metric_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -// @ts-ignore -import { TimeBuckets } from '../../time_buckets'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const detectedTimezone = moment.tz.guess(); const tzOffset = moment().format('Z'); @@ -67,7 +65,7 @@ export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHist export const dateHistogramBucketAgg = new BucketAggType({ name: BUCKET_TYPES.DATE_HISTOGRAM, - title: i18n.translate('common.ui.aggTypes.buckets.dateHistogramTitle', { + title: i18n.translate('data.search.aggs.buckets.dateHistogramTitle', { defaultMessage: 'Date Histogram', }), ordered: { @@ -81,7 +79,7 @@ export const dateHistogramBucketAgg = new BucketAggType { describe('getRequestAggs', () => { describe('initial aggregation creation', () => { - let aggConfigs: AggConfigs; + let aggConfigs: IAggConfigs; let geoHashGridAgg: IBucketGeoHashGridAggConfig; beforeEach(() => { diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts similarity index 96% rename from src/legacy/ui/public/agg_types/buckets/geo_hash.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts index b2519df6fb175..afd4e18dd266c 100644 --- a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts @@ -19,9 +19,9 @@ import { i18n } from '@kbn/i18n'; import { geohashColumns } from 'ui/vis/map/decode_geo_hash'; -import chrome from '../../chrome'; +import chrome from 'ui/chrome'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { geoContains, scaleBounds, GeoBoundingBox } from './lib/geo_utils'; import { BUCKET_TYPES } from './bucket_agg_types'; @@ -68,7 +68,7 @@ function getPrecision(val: string) { const isOutsideCollar = (bounds: GeoBoundingBox, collar: MapCollar) => bounds && collar && !geoContains(collar, bounds); -const geohashGridTitle = i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', { +const geohashGridTitle = i18n.translate('data.search.aggs.buckets.geohashGridTitle', { defaultMessage: 'Geohash', }); diff --git a/src/legacy/ui/public/agg_types/buckets/geo_tile.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts similarity index 92% rename from src/legacy/ui/public/agg_types/buckets/geo_tile.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts index ef71e3947566a..57e8f6e8c5ded 100644 --- a/src/legacy/ui/public/agg_types/buckets/geo_tile.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts @@ -23,11 +23,11 @@ import { AggConfigOptions } from '../agg_config'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { IBucketAggConfig } from './_bucket_agg_type'; import { METRIC_TYPES } from '../metrics/metric_agg_types'; -const geotileGridTitle = i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', { +const geotileGridTitle = i18n.translate('data.search.aggs.buckets.geotileGridTitle', { defaultMessage: 'Geotile', }); diff --git a/src/legacy/ui/public/agg_types/buckets/histogram.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/histogram.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts similarity index 96% rename from src/legacy/ui/public/agg_types/buckets/histogram.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts index 44327c7c19e6d..f7e9ef45961e0 100644 --- a/src/legacy/ui/public/agg_types/buckets/histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts @@ -24,7 +24,7 @@ import { toastNotifications } from 'ui/notify'; import { npStart } from 'ui/new_platform'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterHistogram } from './create_filter/histogram'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { BUCKET_TYPES } from './bucket_agg_types'; export interface AutoBounds { @@ -41,7 +41,7 @@ const getUIConfig = () => npStart.core.uiSettings; export const histogramBucketAgg = new BucketAggType({ name: BUCKET_TYPES.HISTOGRAM, - title: i18n.translate('common.ui.aggTypes.buckets.histogramTitle', { + title: i18n.translate('data.search.aggs.buckets.histogramTitle', { defaultMessage: 'Histogram', }), ordered: {}, @@ -117,7 +117,7 @@ export const histogramBucketAgg = new BucketAggType({ .catch((e: Error) => { if (e.name === 'AbortError') return; toastNotifications.addWarning( - i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', { + i18n.translate('data.search.aggs.histogram.missingMaxMinValuesWarning', { defaultMessage: 'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.', }) diff --git a/src/legacy/ui/public/agg_types/buckets/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts similarity index 93% rename from src/legacy/ui/public/agg_types/buckets/ip_range.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts index 41141dabf507c..e5497bef49165 100644 --- a/src/legacy/ui/public/agg_types/buckets/ip_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts @@ -25,9 +25,9 @@ import { BUCKET_TYPES } from './bucket_agg_types'; // @ts-ignore import { createFilterIpRange } from './create_filter/ip_range'; -import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; -const ipRangeTitle = i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', { +const ipRangeTitle = i18n.translate('data.search.aggs.buckets.ipRangeTitle', { defaultMessage: 'IPv4 Range', }); @@ -57,7 +57,7 @@ export const ipRangeBucketAgg = new BucketAggType({ return new IpRangeFormat(); }, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.ipRangeLabel', { + return i18n.translate('data.search.aggs.buckets.ipRangeLabel', { defaultMessage: '{fieldName} IP ranges', values: { fieldName: aggConfig.getFieldDisplayName(), diff --git a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts similarity index 95% rename from src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts index aadbbc8c82276..30c4e400fb806 100644 --- a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Ipv4Address } from '../../../../../../plugins/kibana_utils/public'; +import { Ipv4Address } from '../../../../../../../../plugins/kibana_utils/public'; const NUM_BITS = 32; diff --git a/src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts diff --git a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts diff --git a/src/legacy/ui/public/agg_types/buckets/range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/range.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts index dd85c3b31939f..4c0fa7311461e 100644 --- a/src/legacy/ui/public/agg_types/buckets/range.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts @@ -19,7 +19,7 @@ import { AggConfigs } from '../agg_configs'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { fieldFormats } from '../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/buckets/range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts similarity index 89% rename from src/legacy/ui/public/agg_types/buckets/range.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts index f24473e0c68aa..f35db2cc759bd 100644 --- a/src/legacy/ui/public/agg_types/buckets/range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType } from './_bucket_agg_type'; -import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { RangeKey } from './range_key'; import { createFilterRange } from './create_filter/range'; import { BUCKET_TYPES } from './bucket_agg_types'; @@ -27,7 +27,7 @@ import { BUCKET_TYPES } from './bucket_agg_types'; const keyCaches = new WeakMap(); const formats = new WeakMap(); -const rangeTitle = i18n.translate('common.ui.aggTypes.buckets.rangeTitle', { +const rangeTitle = i18n.translate('data.search.aggs.buckets.rangeTitle', { defaultMessage: 'Range', }); @@ -36,7 +36,7 @@ export const rangeBucketAgg = new BucketAggType({ title: rangeTitle, createFilter: createFilterRange, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.rangesLabel', { + return i18n.translate('data.search.aggs.aggTypesLabel', { defaultMessage: '{fieldName} ranges', values: { fieldName: aggConfig.getFieldDisplayName(), @@ -69,7 +69,7 @@ export const rangeBucketAgg = new BucketAggType({ const format = agg.fieldOwnFormatter(); const gte = '\u2265'; const lt = '\u003c'; - return i18n.translate('common.ui.aggTypes.buckets.ranges.rangesFormatMessage', { + return i18n.translate('data.search.aggs.aggTypes.rangesFormatMessage', { defaultMessage: '{gte} {from} and {lt} {to}', values: { gte, diff --git a/src/legacy/ui/public/agg_types/buckets/range_key.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range_key.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/range_key.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/range_key.ts diff --git a/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts similarity index 96% rename from src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts index 8db9226e41eec..37b829bfc20fb 100644 --- a/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts @@ -18,6 +18,7 @@ */ import { AggConfigs } from '../index'; +import { IAggConfigs } from '../types'; import { BUCKET_TYPES } from './bucket_agg_types'; import { significantTermsBucketAgg } from './significant_terms'; import { IBucketAggConfig } from './_bucket_agg_type'; @@ -56,7 +57,7 @@ describe('Significant Terms Agg', () => { ); }; - const testSerializeAndWrite = (aggs: AggConfigs) => { + const testSerializeAndWrite = (aggs: IAggConfigs) => { const agg = aggs.aggs[0]; const { [BUCKET_TYPES.SIGNIFICANT_TERMS]: params } = agg.toDsl(); diff --git a/src/legacy/ui/public/agg_types/buckets/significant_terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts similarity index 82% rename from src/legacy/ui/public/agg_types/buckets/significant_terms.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts index 38ca0768d3bc1..bc6c63d569b11 100644 --- a/src/legacy/ui/public/agg_types/buckets/significant_terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts @@ -22,9 +22,9 @@ import { BucketAggType } from './_bucket_agg_type'; import { createFilterTerms } from './create_filter/terms'; import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const significantTermsTitle = i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', { +const significantTermsTitle = i18n.translate('data.search.aggs.buckets.significantTermsTitle', { defaultMessage: 'Significant Terms', }); @@ -32,7 +32,7 @@ export const significantTermsBucketAgg = new BucketAggType({ name: BUCKET_TYPES.SIGNIFICANT_TERMS, title: significantTermsTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.significantTermsLabel', { + return i18n.translate('data.search.aggs.buckets.significantTermsLabel', { defaultMessage: 'Top {size} unusual terms in {fieldName}', values: { size: aggConfig.params.size, @@ -54,7 +54,7 @@ export const significantTermsBucketAgg = new BucketAggType({ }, { name: 'exclude', - displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.excludeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.significantTerms.excludeLabel', { defaultMessage: 'Exclude', }), type: 'string', @@ -64,7 +64,7 @@ export const significantTermsBucketAgg = new BucketAggType({ }, { name: 'include', - displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.significantTerms.includeLabel', { defaultMessage: 'Include', }), type: 'string', diff --git a/src/legacy/ui/public/agg_types/buckets/terms.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/terms.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/terms.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts similarity index 85% rename from src/legacy/ui/public/agg_types/buckets/terms.ts rename to src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts index 4ced1417402b5..b41b16af122fa 100644 --- a/src/legacy/ui/public/agg_types/buckets/terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts @@ -19,19 +19,20 @@ import { noop } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { - getRequestInspectorStats, - getResponseInspectorStats, -} from '../../../../core_plugins/data/public'; +import { getRequestInspectorStats, getResponseInspectorStats } from '../../../index'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketAggConfig } from './_bucket_agg_type'; import { createFilterTerms } from './create_filter/terms'; import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; -import { AggConfigs } from '../agg_configs'; +import { IAggConfigs } from '../agg_configs'; -import { Adapters } from '../../../../../plugins/inspector/public'; -import { ISearchSource, fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { Adapters } from '../../../../../../../plugins/inspector/public'; +import { + ISearchSource, + fieldFormats, + KBN_FIELD_TYPES, +} from '../../../../../../../plugins/data/public'; import { buildOtherBucketAgg, @@ -68,7 +69,7 @@ const [orderAggSchema] = new Schemas([ }, ]).all; -const termsTitle = i18n.translate('common.ui.aggTypes.buckets.termsTitle', { +const termsTitle = i18n.translate('data.search.aggs.buckets.termsTitle', { defaultMessage: 'Terms', }); @@ -98,7 +99,7 @@ export const termsBucketAgg = new BucketAggType({ createFilter: createFilterTerms, postFlightRequest: async ( resp: any, - aggConfigs: AggConfigs, + aggConfigs: IAggConfigs, aggConfig: IBucketAggConfig, searchSource: ISearchSource, inspectorAdapters: Adapters, @@ -113,11 +114,11 @@ export const termsBucketAgg = new BucketAggType({ nestedSearchSource.setField('aggs', filterAgg); const request = inspectorAdapters.requests.start( - i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketTitle', { + i18n.translate('data.search.aggs.buckets.terms.otherBucketTitle', { defaultMessage: 'Other bucket', }), { - description: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketDescription', { + description: i18n.translate('data.search.aggs.buckets.terms.otherBucketDescription', { defaultMessage: 'This request counts the number of documents that fall ' + 'outside the criterion of the data buckets.', @@ -212,13 +213,13 @@ export const termsBucketAgg = new BucketAggType({ default: 'desc', options: [ { - text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', { + text: i18n.translate('data.search.aggs.buckets.terms.orderDescendingTitle', { defaultMessage: 'Descending', }), value: 'desc', }, { - text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', { + text: i18n.translate('data.search.aggs.buckets.terms.orderAscendingTitle', { defaultMessage: 'Ascending', }), value: 'asc', @@ -238,10 +239,10 @@ export const termsBucketAgg = new BucketAggType({ { name: 'otherBucketLabel', type: 'string', - default: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketLabel', { + default: i18n.translate('data.search.aggs.buckets.terms.otherBucketLabel', { defaultMessage: 'Other', }), - displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', { + displayName: i18n.translate('data.search.aggs.otherBucket.labelForOtherBucketLabel', { defaultMessage: 'Label for other bucket', }), shouldShow: agg => agg.getParam('otherBucket'), @@ -254,13 +255,13 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'missingBucketLabel', - default: i18n.translate('common.ui.aggTypes.buckets.terms.missingBucketLabel', { + default: i18n.translate('data.search.aggs.buckets.terms.missingBucketLabel', { defaultMessage: 'Missing', description: `Default label used in charts when documents are missing a field. Visible when you create a chart with a terms aggregation and enable "Show missing values"`, }), type: 'string', - displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', { + displayName: i18n.translate('data.search.aggs.otherBucket.labelForMissingValuesLabel', { defaultMessage: 'Label for missing values', }), shouldShow: agg => agg.getParam('missingBucket'), @@ -268,7 +269,7 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'exclude', - displayName: i18n.translate('common.ui.aggTypes.buckets.terms.excludeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.terms.excludeLabel', { defaultMessage: 'Exclude', }), type: 'string', @@ -278,7 +279,7 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'include', - displayName: i18n.translate('common.ui.aggTypes.buckets.terms.includeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.terms.includeLabel', { defaultMessage: 'Include', }), type: 'string', diff --git a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts similarity index 88% rename from src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts index 0344f304877f2..cc1288d339692 100644 --- a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts @@ -17,9 +17,10 @@ * under the License. */ -import { IndexPattern } from '../../../../../plugins/data/public'; +import { IndexPattern } from '../../../../../../../plugins/data/public'; import { AggTypeFilters } from './agg_type_filters'; -import { AggConfig, AggType } from '..'; +import { AggConfig } from '..'; +import { IAggType } from '../types'; describe('AggTypeFilters', () => { let registry: AggTypeFilters; @@ -31,13 +32,13 @@ describe('AggTypeFilters', () => { }); it('should filter nothing without registered filters', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }] as AggType[]; + const aggTypes = [{ name: 'count' }, { name: 'sum' }] as IAggType[]; const filtered = registry.filter(aggTypes, indexPattern, aggConfig); expect(filtered).toEqual(aggTypes); }); it('should pass all aggTypes to the registered filter', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }] as AggType[]; + const aggTypes = [{ name: 'count' }, { name: 'sum' }] as IAggType[]; const filter = jest.fn(); registry.addFilter(filter); registry.filter(aggTypes, indexPattern, aggConfig); @@ -46,7 +47,7 @@ describe('AggTypeFilters', () => { }); it('should allow registered filters to filter out aggTypes', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }, { name: 'avg' }] as AggType[]; + const aggTypes = [{ name: 'count' }, { name: 'sum' }, { name: 'avg' }] as IAggType[]; let filtered = registry.filter(aggTypes, indexPattern, aggConfig); expect(filtered).toEqual(aggTypes); diff --git a/src/legacy/ui/public/agg_types/filter/agg_type_filters.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts similarity index 92% rename from src/legacy/ui/public/agg_types/filter/agg_type_filters.ts rename to src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts index 2cc4a6e962214..d3b38ce041d7e 100644 --- a/src/legacy/ui/public/agg_types/filter/agg_type_filters.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts @@ -17,12 +17,12 @@ * under the License. */ import { IndexPattern } from 'src/plugins/data/public'; -import { AggType, AggConfig } from '..'; +import { IAggConfig, IAggType } from '../types'; type AggTypeFilter = ( - aggType: AggType, + aggType: IAggType, indexPattern: IndexPattern, - aggConfig: AggConfig + aggConfig: IAggConfig ) => boolean; /** @@ -49,7 +49,7 @@ class AggTypeFilters { * @param aggConfig The aggConfig for which the returning list will be used. * @return A filtered list of the passed aggTypes. */ - public filter(aggTypes: AggType[], indexPattern: IndexPattern, aggConfig: AggConfig) { + public filter(aggTypes: IAggType[], indexPattern: IndexPattern, aggConfig: IAggConfig) { const allFilters = Array.from(this.filters); const allowedAggTypes = aggTypes.filter(aggType => { const isAggTypeAllowed = allFilters.every(filter => filter(aggType, indexPattern, aggConfig)); diff --git a/src/legacy/ui/public/agg_types/filter/index.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts similarity index 100% rename from src/legacy/ui/public/agg_types/filter/index.ts rename to src/legacy/core_plugins/data/public/search/aggs/filter/index.ts diff --git a/src/legacy/ui/public/agg_types/filter/prop_filter.test.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/filter/prop_filter.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.test.ts diff --git a/src/legacy/ui/public/agg_types/filter/prop_filter.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.ts similarity index 100% rename from src/legacy/ui/public/agg_types/filter/prop_filter.ts rename to src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.ts diff --git a/src/legacy/ui/public/agg_types/index.test.ts b/src/legacy/core_plugins/data/public/search/aggs/index.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/index.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/index.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/index.ts b/src/legacy/core_plugins/data/public/search/aggs/index.ts new file mode 100644 index 0000000000000..0fef7f38aae74 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/index.ts @@ -0,0 +1,52 @@ +/* + * 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 { aggTypes } from './agg_types'; +export { AggType } from './agg_type'; +export { AggConfig } from './agg_config'; +export { AggConfigs } from './agg_configs'; +export { FieldParamType } from './param_types'; +export { MetricAggType } from './metrics/metric_agg_type'; +export { AggTypeFilters } from './filter'; +export { aggTypeFieldFilters, AggTypeFieldFilters } from './param_types/filter'; +export { + parentPipelineAggHelper, + parentPipelineType, +} from './metrics/lib/parent_pipeline_agg_helper'; +export { + siblingPipelineAggHelper, + siblingPipelineType, +} from './metrics/lib/sibling_pipeline_agg_helper'; + +// static code +export { AggParamType } from './param_types/agg'; +export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; +export { intervalOptions } from './buckets/_interval_options'; // only used in Discover +export { isDateHistogramBucketAggConfig, setBounds } from './buckets/date_histogram'; +export { termsAggFilter } from './buckets/terms'; +export { isType, isStringType } from './buckets/migrate_include_exclude_format'; +export { CidrMask } from './buckets/lib/cidr_mask'; +export { convertDateRangeToString } from './buckets/date_range'; +export { convertIPRangeToString } from './buckets/ip_range'; +export { aggTypeFilters, propFilter } from './filter'; +export { OptionedParamType } from './param_types/optioned'; +export { isValidJson, isValidInterval } from './utils'; +export { BUCKET_TYPES } from './buckets/bucket_agg_types'; +export { METRIC_TYPES } from './metrics/metric_agg_types'; +export { ISchemas, Schema, Schemas } from './schemas'; diff --git a/src/legacy/ui/public/agg_types/metrics/avg.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts similarity index 85% rename from src/legacy/ui/public/agg_types/metrics/avg.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts index 0222a8e543223..b80671a43d2af 100644 --- a/src/legacy/ui/public/agg_types/metrics/avg.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts @@ -20,9 +20,9 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const averageTitle = i18n.translate('common.ui.aggTypes.metrics.averageTitle', { +const averageTitle = i18n.translate('data.search.aggs.metrics.averageTitle', { defaultMessage: 'Average', }); @@ -30,7 +30,7 @@ export const avgMetricAgg = new MetricAggType({ name: METRIC_TYPES.AVG, title: averageTitle, makeLabel: aggConfig => { - return i18n.translate('common.ui.aggTypes.metrics.averageLabel', { + return i18n.translate('data.search.aggs.metrics.averageLabel', { defaultMessage: 'Average {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_avg.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts similarity index 91% rename from src/legacy/ui/public/agg_types/metrics/bucket_avg.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts index 7142546dbd494..9fb28f8631bc6 100644 --- a/src/legacy/ui/public/agg_types/metrics/bucket_avg.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts @@ -25,11 +25,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallAverageLabel = i18n.translate('common.ui.aggTypes.metrics.overallAverageLabel', { +const overallAverageLabel = i18n.translate('data.search.aggs.metrics.overallAverageLabel', { defaultMessage: 'overall average', }); -const averageBucketTitle = i18n.translate('common.ui.aggTypes.metrics.averageBucketTitle', { +const averageBucketTitle = i18n.translate('data.search.aggs.metrics.averageBucketTitle', { defaultMessage: 'Average Bucket', }); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_max.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/bucket_max.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts index aa5b0521709a5..83837f0de5114 100644 --- a/src/legacy/ui/public/agg_types/metrics/bucket_max.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts @@ -24,11 +24,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallMaxLabel = i18n.translate('common.ui.aggTypes.metrics.overallMaxLabel', { +const overallMaxLabel = i18n.translate('data.search.aggs.metrics.overallMaxLabel', { defaultMessage: 'overall max', }); -const maxBucketTitle = i18n.translate('common.ui.aggTypes.metrics.maxBucketTitle', { +const maxBucketTitle = i18n.translate('data.search.aggs.metrics.maxBucketTitle', { defaultMessage: 'Max Bucket', }); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_min.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/bucket_min.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts index b5c0b8865e106..d96197693dc2e 100644 --- a/src/legacy/ui/public/agg_types/metrics/bucket_min.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts @@ -22,11 +22,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallMinLabel = i18n.translate('common.ui.aggTypes.metrics.overallMinLabel', { +const overallMinLabel = i18n.translate('data.search.aggs.metrics.overallMinLabel', { defaultMessage: 'overall min', }); -const minBucketTitle = i18n.translate('common.ui.aggTypes.metrics.minBucketTitle', { +const minBucketTitle = i18n.translate('data.search.aggs.metrics.minBucketTitle', { defaultMessage: 'Min Bucket', }); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/bucket_sum.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts index d4faa81c4041c..1f9392c5bec35 100644 --- a/src/legacy/ui/public/agg_types/metrics/bucket_sum.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts @@ -23,11 +23,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallSumLabel = i18n.translate('common.ui.aggTypes.metrics.overallSumLabel', { +const overallSumLabel = i18n.translate('data.search.aggs.metrics.overallSumLabel', { defaultMessage: 'overall sum', }); -const sumBucketTitle = i18n.translate('common.ui.aggTypes.metrics.sumBucketTitle', { +const sumBucketTitle = i18n.translate('data.search.aggs.metrics.sumBucketTitle', { defaultMessage: 'Sum Bucket', }); diff --git a/src/legacy/ui/public/agg_types/metrics/cardinality.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts similarity index 86% rename from src/legacy/ui/public/agg_types/metrics/cardinality.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts index c69ffae3b4871..147e925521088 100644 --- a/src/legacy/ui/public/agg_types/metrics/cardinality.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts @@ -21,9 +21,9 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const uniqueCountTitle = i18n.translate('common.ui.aggTypes.metrics.uniqueCountTitle', { +const uniqueCountTitle = i18n.translate('data.search.aggs.metrics.uniqueCountTitle', { defaultMessage: 'Unique Count', }); @@ -31,7 +31,7 @@ export const cardinalityMetricAgg = new MetricAggType({ name: METRIC_TYPES.CARDINALITY, title: uniqueCountTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.uniqueCountLabel', { + return i18n.translate('data.search.aggs.metrics.uniqueCountLabel', { defaultMessage: 'Unique count of {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/count.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts similarity index 87% rename from src/legacy/ui/public/agg_types/metrics/count.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts index 22a939cd9a3fd..14a9bd073ff2b 100644 --- a/src/legacy/ui/public/agg_types/metrics/count.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts @@ -19,18 +19,18 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; export const countMetricAgg = new MetricAggType({ name: METRIC_TYPES.COUNT, - title: i18n.translate('common.ui.aggTypes.metrics.countTitle', { + title: i18n.translate('data.search.aggs.metrics.countTitle', { defaultMessage: 'Count', }), hasNoDsl: true, makeLabel() { - return i18n.translate('common.ui.aggTypes.metrics.countLabel', { + return i18n.translate('data.search.aggs.metrics.countLabel', { defaultMessage: 'Count', }); }, diff --git a/src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts similarity index 88% rename from src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts index bad2de8cb16dc..a5d02459900bb 100644 --- a/src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const cumulativeSumLabel = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumLabel', { +const cumulativeSumLabel = i18n.translate('data.search.aggs.metrics.cumulativeSumLabel', { defaultMessage: 'cumulative sum', }); -const cumulativeSumTitle = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumTitle', { +const cumulativeSumTitle = i18n.translate('data.search.aggs.metrics.cumulativeSumTitle', { defaultMessage: 'Cumulative Sum', }); diff --git a/src/legacy/ui/public/agg_types/metrics/derivative.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/derivative.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts index 42921621a2933..1169a527b0668 100644 --- a/src/legacy/ui/public/agg_types/metrics/derivative.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const derivativeLabel = i18n.translate('common.ui.aggTypes.metrics.derivativeLabel', { +const derivativeLabel = i18n.translate('data.search.aggs.metrics.derivativeLabel', { defaultMessage: 'derivative', }); -const derivativeTitle = i18n.translate('common.ui.aggTypes.metrics.derivativeTitle', { +const derivativeTitle = i18n.translate('data.search.aggs.metrics.derivativeTitle', { defaultMessage: 'Derivative', }); diff --git a/src/legacy/ui/public/agg_types/metrics/geo_bounds.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts similarity index 84% rename from src/legacy/ui/public/agg_types/metrics/geo_bounds.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts index b8ce03cdf11ec..53bc72f9ce1da 100644 --- a/src/legacy/ui/public/agg_types/metrics/geo_bounds.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts @@ -20,13 +20,13 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const geoBoundsTitle = i18n.translate('common.ui.aggTypes.metrics.geoBoundsTitle', { +const geoBoundsTitle = i18n.translate('data.search.aggs.metrics.geoBoundsTitle', { defaultMessage: 'Geo Bounds', }); -const geoBoundsLabel = i18n.translate('common.ui.aggTypes.metrics.geoBoundsLabel', { +const geoBoundsLabel = i18n.translate('data.search.aggs.metrics.geoBoundsLabel', { defaultMessage: 'Geo Bounds', }); diff --git a/src/legacy/ui/public/agg_types/metrics/geo_centroid.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts similarity index 84% rename from src/legacy/ui/public/agg_types/metrics/geo_centroid.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts index 5313e31796a5b..a79b2b34ad1ca 100644 --- a/src/legacy/ui/public/agg_types/metrics/geo_centroid.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts @@ -20,13 +20,13 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const geoCentroidTitle = i18n.translate('common.ui.aggTypes.metrics.geoCentroidTitle', { +const geoCentroidTitle = i18n.translate('data.search.aggs.metrics.geoCentroidTitle', { defaultMessage: 'Geo Centroid', }); -const geoCentroidLabel = i18n.translate('common.ui.aggTypes.metrics.geoCentroidLabel', { +const geoCentroidLabel = i18n.translate('data.search.aggs.metrics.geoCentroidLabel', { defaultMessage: 'Geo Centroid', }); diff --git a/src/legacy/ui/public/agg_types/metrics/lib/get_response_agg_config_class.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/get_response_agg_config_class.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts similarity index 94% rename from src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts index 4d558e50304e6..0d1b2472bb8e2 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts @@ -36,7 +36,7 @@ const metricAggFilter = [ '!geo_centroid', ]; -const metricAggTitle = i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { +const metricAggTitle = i18n.translate('data.search.aggs.metrics.metricAggTitle', { defaultMessage: 'Metric agg', }); @@ -51,7 +51,7 @@ const [metricAggSchema] = new Schemas([ ]).all; const parentPipelineType = i18n.translate( - 'common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle', + 'data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle', { defaultMessage: 'Parent Pipeline Aggregations', } diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts similarity index 94% rename from src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts index 684fe721a754a..bc0359b2a213d 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts @@ -17,13 +17,13 @@ * under the License. */ -import { AggConfigs } from '../../agg_configs'; +import { IAggConfigs } from '../../agg_configs'; import { IMetricAggConfig } from '../metric_agg_type'; export const parentPipelineAggWriter = ( agg: IMetricAggConfig, output: Record, - aggConfigs?: AggConfigs + aggConfigs?: IAggConfigs ): void => { const customMetric = agg.getParam('customMetric'); const metricAgg = agg.getParam('metricAgg'); diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts similarity index 93% rename from src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts index 9dd737bd6708e..3956bda1812ad 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts @@ -47,7 +47,7 @@ const [metricAggSchema] = new Schemas([ { group: 'none', name: 'metricAgg', - title: i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { + title: i18n.translate('data.search.aggs.metrics.metricAggTitle', { defaultMessage: 'Metric agg', }), aggFilter: metricAggFilter, @@ -57,7 +57,7 @@ const [metricAggSchema] = new Schemas([ const [bucketAggSchema] = new Schemas([ { group: 'none', - title: i18n.translate('common.ui.aggTypes.metrics.bucketAggTitle', { + title: i18n.translate('data.search.aggs.metrics.bucketAggTitle', { defaultMessage: 'Bucket agg', }), name: 'bucketAgg', @@ -66,7 +66,7 @@ const [bucketAggSchema] = new Schemas([ ]).all; const siblingPipelineType = i18n.translate( - 'common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle', + 'data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle', { defaultMessage: 'Sibling pipeline aggregations', } diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts diff --git a/src/legacy/ui/public/agg_types/metrics/max.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts similarity index 86% rename from src/legacy/ui/public/agg_types/metrics/max.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts index 5c43511acee72..d561788936b51 100644 --- a/src/legacy/ui/public/agg_types/metrics/max.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts @@ -20,9 +20,9 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const maxTitle = i18n.translate('common.ui.aggTypes.metrics.maxTitle', { +const maxTitle = i18n.translate('data.search.aggs.metrics.maxTitle', { defaultMessage: 'Max', }); @@ -30,7 +30,7 @@ export const maxMetricAgg = new MetricAggType({ name: METRIC_TYPES.MAX, title: maxTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.maxLabel', { + return i18n.translate('data.search.aggs.metrics.maxLabel', { defaultMessage: 'Max {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/median.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts similarity index 95% rename from src/legacy/ui/public/agg_types/metrics/median.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts index 819c24f135cdc..9affb0e3b2814 100644 --- a/src/legacy/ui/public/agg_types/metrics/median.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts @@ -17,13 +17,13 @@ * under the License. */ -import { AggConfigs } from '../agg_configs'; +import { AggConfigs, IAggConfigs } from '../agg_configs'; import { METRIC_TYPES } from './metric_agg_types'; jest.mock('ui/new_platform'); describe('AggTypeMetricMedianProvider class', () => { - let aggConfigs: AggConfigs; + let aggConfigs: IAggConfigs; beforeEach(() => { const field = { diff --git a/src/legacy/ui/public/agg_types/metrics/median.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts similarity index 88% rename from src/legacy/ui/public/agg_types/metrics/median.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts index 5792d4a7c2ba3..be080aaa5ee6f 100644 --- a/src/legacy/ui/public/agg_types/metrics/median.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts @@ -22,9 +22,9 @@ import { METRIC_TYPES } from './metric_agg_types'; // @ts-ignore import { percentilesMetricAgg } from './percentiles'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const medianTitle = i18n.translate('common.ui.aggTypes.metrics.medianTitle', { +const medianTitle = i18n.translate('data.search.aggs.metrics.medianTitle', { defaultMessage: 'Median', }); @@ -33,7 +33,7 @@ export const medianMetricAgg = new MetricAggType({ dslName: 'percentiles', title: medianTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.medianLabel', { + return i18n.translate('data.search.aggs.metrics.medianLabel', { defaultMessage: 'Median {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts index 5cd3dffb10b9d..3bae7b92618dc 100644 --- a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts @@ -23,7 +23,8 @@ import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; import { AggConfig } from '../agg_config'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { FilterFieldTypes } from '../param_types/field'; export interface IMetricAggConfig extends AggConfig { type: InstanceType; @@ -31,7 +32,7 @@ export interface IMetricAggConfig extends AggConfig { export interface MetricAggParam extends AggParamType { - filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*'; + filterFieldTypes?: FilterFieldTypes; onlyAggregatable?: boolean; } @@ -43,6 +44,9 @@ interface MetricAggTypeConfig subtype?: string; } +// TODO need to make a more explicit interface for this +export type IMetricAggType = MetricAggType; + export class MetricAggType extends AggType< TMetricAggConfig, MetricAggParam @@ -83,7 +87,7 @@ export class MetricAggType { const field = { diff --git a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts index cbd46e3f5b28d..38b47a7e97d2f 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts @@ -24,7 +24,7 @@ import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_respons import { getPercentileValue } from './percentiles_get_value'; import { METRIC_TYPES } from './metric_agg_types'; -import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; // required by the values editor @@ -41,7 +41,7 @@ const valueProps = { const customLabel = this.getParam('customLabel'); const label = customLabel || this.getFieldDisplayName(); - return i18n.translate('common.ui.aggTypes.metrics.percentileRanks.valuePropsLabel', { + return i18n.translate('data.search.aggs.metrics.percentileRanks.valuePropsLabel', { defaultMessage: 'Percentile rank {format} of "{label}"', values: { format: format.convert(this.key, 'text'), label }, }); @@ -50,11 +50,11 @@ const valueProps = { export const percentileRanksMetricAgg = new MetricAggType({ name: METRIC_TYPES.PERCENTILE_RANKS, - title: i18n.translate('common.ui.aggTypes.metrics.percentileRanksTitle', { + title: i18n.translate('data.search.aggs.metrics.percentileRanksTitle', { defaultMessage: 'Percentile Ranks', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.percentileRanksLabel', { + return i18n.translate('data.search.aggs.metrics.percentileRanksLabel', { defaultMessage: 'Percentile ranks of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts similarity index 95% rename from src/legacy/ui/public/agg_types/metrics/percentiles.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts index c9f4bcc3862a0..dd1aaca973e47 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts @@ -18,13 +18,13 @@ */ import { IPercentileAggConfig, percentilesMetricAgg } from './percentiles'; -import { AggConfigs } from '../agg_configs'; +import { AggConfigs, IAggConfigs } from '../agg_configs'; import { METRIC_TYPES } from './metric_agg_types'; jest.mock('ui/new_platform'); describe('AggTypesMetricsPercentilesProvider class', () => { - let aggConfigs: AggConfigs; + let aggConfigs: IAggConfigs; beforeEach(() => { const field = { diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts similarity index 88% rename from src/legacy/ui/public/agg_types/metrics/percentiles.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts index 040324d8da5df..39dc0d0f181e9 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentiles.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; import { getPercentileValue } from './percentiles_get_value'; @@ -36,7 +36,7 @@ const valueProps = { const customLabel = this.getParam('customLabel'); const label = customLabel || this.getFieldDisplayName(); - return i18n.translate('common.ui.aggTypes.metrics.percentiles.valuePropsLabel', { + return i18n.translate('data.search.aggs.metrics.percentiles.valuePropsLabel', { defaultMessage: '{percentile} percentile of {label}', values: { percentile: ordinalSuffix(this.key), label }, }); @@ -45,11 +45,11 @@ const valueProps = { export const percentilesMetricAgg = new MetricAggType({ name: METRIC_TYPES.PERCENTILES, - title: i18n.translate('common.ui.aggTypes.metrics.percentilesTitle', { + title: i18n.translate('data.search.aggs.metrics.percentilesTitle', { defaultMessage: 'Percentiles', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.percentilesLabel', { + return i18n.translate('data.search.aggs.metrics.percentilesLabel', { defaultMessage: 'Percentiles of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles_get_value.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/percentiles_get_value.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts diff --git a/src/legacy/ui/public/agg_types/metrics/serial_diff.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/serial_diff.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts index bb5431fbbefd9..5af6e1952d135 100644 --- a/src/legacy/ui/public/agg_types/metrics/serial_diff.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const serialDiffTitle = i18n.translate('common.ui.aggTypes.metrics.serialDiffTitle', { +const serialDiffTitle = i18n.translate('data.search.aggs.metrics.serialDiffTitle', { defaultMessage: 'Serial Diff', }); -const serialDiffLabel = i18n.translate('common.ui.aggTypes.metrics.serialDiffLabel', { +const serialDiffLabel = i18n.translate('data.search.aggs.metrics.serialDiffLabel', { defaultMessage: 'serial diff', }); diff --git a/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/std_deviation.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts similarity index 85% rename from src/legacy/ui/public/agg_types/metrics/std_deviation.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts index b2e6d3b3ca4d0..caf3bb71dd89a 100644 --- a/src/legacy/ui/public/agg_types/metrics/std_deviation.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; interface ValProp { valProp: string[]; @@ -51,7 +51,7 @@ const responseAggConfigProps = { keyedDetails(this: IStdDevAggConfig, customLabel: string, fieldDisplayName: string) { const label = customLabel || - i18n.translate('common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel', { + i18n.translate('data.search.aggs.metrics.standardDeviation.keyDetailsLabel', { defaultMessage: 'Standard Deviation of {fieldDisplayName}', values: { fieldDisplayName }, }); @@ -59,14 +59,14 @@ const responseAggConfigProps = { return { std_lower: { valProp: ['std_deviation_bounds', 'lower'], - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle', { defaultMessage: 'Lower {label}', values: { label }, }), }, std_upper: { valProp: ['std_deviation_bounds', 'upper'], - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle', { defaultMessage: 'Upper {label}', values: { label }, }), @@ -78,11 +78,11 @@ const responseAggConfigProps = { export const stdDeviationMetricAgg = new MetricAggType({ name: METRIC_TYPES.STD_DEV, dslName: 'extended_stats', - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviationTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviationTitle', { defaultMessage: 'Standard Deviation', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.standardDeviationLabel', { + return i18n.translate('data.search.aggs.metrics.standardDeviationLabel', { defaultMessage: 'Standard Deviation of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts similarity index 86% rename from src/legacy/ui/public/agg_types/metrics/sum.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts index ce79c761ce799..f3450ba1700c8 100644 --- a/src/legacy/ui/public/agg_types/metrics/sum.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts @@ -20,9 +20,9 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const sumTitle = i18n.translate('common.ui.aggTypes.metrics.sumTitle', { +const sumTitle = i18n.translate('data.search.aggs.metrics.sumTitle', { defaultMessage: 'Sum', }); @@ -30,7 +30,7 @@ export const sumMetricAgg = new MetricAggType({ name: METRIC_TYPES.SUM, title: sumTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.sumLabel', { + return i18n.translate('data.search.aggs.metrics.sumLabel', { defaultMessage: 'Sum of {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts similarity index 99% rename from src/legacy/ui/public/agg_types/metrics/top_hit.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts index 3e861c052d367..a973de4fe8659 100644 --- a/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts @@ -21,7 +21,7 @@ import { dropRight, last } from 'lodash'; import { topHitMetricAgg } from './top_hit'; import { AggConfigs } from '../agg_configs'; import { IMetricAggConfig } from './metric_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/metrics/top_hit.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts similarity index 82% rename from src/legacy/ui/public/agg_types/metrics/top_hit.ts rename to src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts index 43fe33bdebeb9..3112d882bb87e 100644 --- a/src/legacy/ui/public/agg_types/metrics/top_hit.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts @@ -20,9 +20,8 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; -import { aggTypeFieldFilters } from '../param_types/filter'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; // @ts-ignore import { wrapWithInlineComp } from '../buckets/inline_comp_wrapper'; @@ -33,27 +32,16 @@ const isNumericFieldSelected = (agg: IMetricAggConfig) => { return field && field.type && field.type === KBN_FIELD_TYPES.NUMBER; }; -aggTypeFieldFilters.addFilter((field, aggConfig) => { - if ( - aggConfig.type.name !== METRIC_TYPES.TOP_HITS || - _.get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false) - ) { - return true; - } - - return field.type === KBN_FIELD_TYPES.NUMBER; -}); - export const topHitMetricAgg = new MetricAggType({ name: METRIC_TYPES.TOP_HITS, - title: i18n.translate('common.ui.aggTypes.metrics.topHitTitle', { + title: i18n.translate('data.search.aggs.metrics.topHitTitle', { defaultMessage: 'Top Hit', }), makeLabel(aggConfig) { - const lastPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.lastPrefixLabel', { + const lastPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.lastPrefixLabel', { defaultMessage: 'Last', }); - const firstPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.firstPrefixLabel', { + const firstPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.firstPrefixLabel', { defaultMessage: 'First', }); @@ -75,7 +63,10 @@ export const topHitMetricAgg = new MetricAggType({ name: 'field', type: 'field', onlyAggregatable: false, - filterFieldTypes: '*', + filterFieldTypes: (aggConfig: IMetricAggConfig) => + _.get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false) + ? '*' + : KBN_FIELD_TYPES.NUMBER, write(agg, output) { const field = agg.getParam('field'); output.params = {}; @@ -106,7 +97,7 @@ export const topHitMetricAgg = new MetricAggType({ type: 'optioned', options: [ { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.minLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.minLabel', { defaultMessage: 'Min', }), isCompatible: isNumericFieldSelected, @@ -114,7 +105,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'min', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.maxLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.maxLabel', { defaultMessage: 'Max', }), isCompatible: isNumericFieldSelected, @@ -122,7 +113,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'max', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.sumLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.sumLabel', { defaultMessage: 'Sum', }), isCompatible: isNumericFieldSelected, @@ -130,7 +121,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'sum', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.averageLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.averageLabel', { defaultMessage: 'Average', }), isCompatible: isNumericFieldSelected, @@ -138,7 +129,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'average', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.concatenateLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.concatenateLabel', { defaultMessage: 'Concatenate', }), isCompatible(aggConfig: IMetricAggConfig) { @@ -174,13 +165,13 @@ export const topHitMetricAgg = new MetricAggType({ default: 'desc', options: [ { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.descendingLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.descendingLabel', { defaultMessage: 'Descending', }), value: 'desc', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.ascendingLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.ascendingLabel', { defaultMessage: 'Ascending', }), value: 'asc', diff --git a/src/legacy/ui/public/agg_types/param_types/agg.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/agg.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/agg.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/agg.ts diff --git a/src/legacy/ui/public/agg_types/param_types/base.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts similarity index 94% rename from src/legacy/ui/public/agg_types/param_types/base.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts index 15ec44e2ca5ae..1523cb03eb966 100644 --- a/src/legacy/ui/public/agg_types/param_types/base.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts @@ -17,9 +17,9 @@ * under the License. */ -import { AggConfigs } from '../agg_configs'; +import { IAggConfigs } from '../agg_configs'; import { AggConfig } from '../agg_config'; -import { FetchOptions, ISearchSource } from '../../../../../plugins/data/public'; +import { FetchOptions, ISearchSource } from '../../../../../../../plugins/data/public'; export class BaseParamType { name: string; @@ -31,7 +31,7 @@ export class BaseParamType { write: ( aggConfig: TAggConfig, output: Record, - aggConfigs?: AggConfigs, + aggConfigs?: IAggConfigs, locals?: Record ) => void; serialize: (value: any, aggConfig?: TAggConfig) => any; diff --git a/src/legacy/ui/public/agg_types/param_types/field.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts similarity index 54% rename from src/legacy/ui/public/agg_types/param_types/field.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts index 9cea2934d7459..fa88754ac60b9 100644 --- a/src/legacy/ui/public/agg_types/param_types/field.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts @@ -17,9 +17,13 @@ * under the License. */ +import { get } from 'lodash'; import { BaseParamType } from './base'; import { FieldParamType } from './field'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { IAggConfig } from '../agg_config'; +import { IMetricAggConfig } from '../metrics/metric_agg_type'; +import { Schema } from '../schemas'; jest.mock('ui/new_platform'); @@ -45,7 +49,11 @@ describe('Field', () => { searchable: true, }, ], - } as any; + }; + + const agg = ({ + getIndexPattern: jest.fn(() => indexPattern), + } as unknown) as IAggConfig; describe('constructor', () => { it('it is an instance of BaseParamType', () => { @@ -65,7 +73,7 @@ describe('Field', () => { type: 'field', }); - const fields = aggParam.getAvailableFields(indexPattern.fields); + const fields = aggParam.getAvailableFields(agg); expect(fields.length).toBe(1); @@ -82,7 +90,58 @@ describe('Field', () => { aggParam.onlyAggregatable = false; - const fields = aggParam.getAvailableFields(indexPattern.fields); + const fields = aggParam.getAvailableFields(agg); + + expect(fields.length).toBe(2); + }); + + it('should return all fields if filterFieldTypes was not specified', () => { + const aggParam = new FieldParamType({ + name: 'field', + type: 'field', + }); + + indexPattern.fields[1].aggregatable = true; + + const fields = aggParam.getAvailableFields(agg); + + expect(fields.length).toBe(2); + }); + + it('should return only numeric fields if filterFieldTypes was specified as a function', () => { + const aggParam = new FieldParamType({ + name: 'field', + type: 'field', + filterFieldTypes: (aggConfig: IMetricAggConfig) => + get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false) + ? '*' + : KBN_FIELD_TYPES.NUMBER, + }); + const fields = aggParam.getAvailableFields(agg); + + expect(fields.length).toBe(1); + expect(fields[0].type).toBe(KBN_FIELD_TYPES.NUMBER); + }); + + it('should return all fields if filterFieldTypes was specified as a function and aggSettings allow string type fields', () => { + const aggParam = new FieldParamType({ + name: 'field', + type: 'field', + filterFieldTypes: (aggConfig: IMetricAggConfig) => + get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false) + ? '*' + : KBN_FIELD_TYPES.NUMBER, + }); + + agg.schema = { + aggSettings: { + top_hits: { + allowStrings: true, + }, + }, + } as Schema; + + const fields = aggParam.getAvailableFields(agg); expect(fields.length).toBe(2); }); diff --git a/src/legacy/ui/public/agg_types/param_types/field.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts similarity index 65% rename from src/legacy/ui/public/agg_types/param_types/field.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts index d01e059c6c616..9a204bb151e2d 100644 --- a/src/legacy/ui/public/agg_types/param_types/field.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts @@ -17,22 +17,27 @@ * under the License. */ -// @ts-ignore import { i18n } from '@kbn/i18n'; -import { AggConfig } from '../agg_config'; -import { SavedObjectNotFound } from '../../../../../plugins/kibana_utils/public'; +import { isFunction } from 'lodash'; +import { npStart } from 'ui/new_platform'; +import { IAggConfig } from '../agg_config'; +import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public'; import { BaseParamType } from './base'; -import { npStart } from '../../new_platform'; import { propFilter } from '../filter'; -import { Field, IFieldList } from '../../../../../plugins/data/public'; -import { isNestedField } from '../../../../../plugins/data/public'; +import { IMetricAggConfig } from '../metrics/metric_agg_type'; +import { Field, isNestedField, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const filterByType = propFilter('type'); +type FieldTypes = KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*'; +export type FilterFieldTypes = ((aggConfig: IMetricAggConfig) => FieldTypes) | FieldTypes; +// TODO need to make a more explicit interface for this +export type IFieldParamType = FieldParamType; + export class FieldParamType extends BaseParamType { required = true; scriptable = true; - filterFieldTypes: string; + filterFieldTypes: FilterFieldTypes; onlyAggregatable: boolean; constructor(config: Record) { @@ -42,20 +47,17 @@ export class FieldParamType extends BaseParamType { this.onlyAggregatable = config.onlyAggregatable !== false; if (!config.write) { - this.write = (aggConfig: AggConfig, output: Record) => { + this.write = (aggConfig: IAggConfig, output: Record) => { const field = aggConfig.getField(); if (!field) { throw new TypeError( - i18n.translate( - 'common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage', - { - defaultMessage: '{fieldParameter} is a required parameter', - values: { - fieldParameter: '"field"', - }, - } - ) + i18n.translate('data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage', { + defaultMessage: '{fieldParameter} is a required parameter', + values: { + fieldParameter: '"field"', + }, + }) ); } @@ -74,7 +76,7 @@ export class FieldParamType extends BaseParamType { return field.name; }; - this.deserialize = (fieldName: string, aggConfig?: AggConfig) => { + this.deserialize = (fieldName: string, aggConfig?: IAggConfig) => { if (!aggConfig) { throw new Error('aggConfig was not provided to FieldParamType deserialize function'); } @@ -85,13 +87,11 @@ export class FieldParamType extends BaseParamType { } // @ts-ignore - const validField = this.getAvailableFields(aggConfig.getIndexPattern().fields).find( - (f: any) => f.name === fieldName - ); + const validField = this.getAvailableFields(aggConfig).find((f: any) => f.name === fieldName); if (!validField) { npStart.core.notifications.toasts.addDanger( i18n.translate( - 'common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage', + 'data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage', { defaultMessage: 'Saved {fieldParameter} parameter is now invalid. Please select a new field.', @@ -110,7 +110,8 @@ export class FieldParamType extends BaseParamType { /** * filter the fields to the available ones */ - getAvailableFields = (fields: IFieldList) => { + getAvailableFields = (aggConfig: IAggConfig) => { + const fields = aggConfig.getIndexPattern().fields; const filteredFields = fields.filter((field: Field) => { const { onlyAggregatable, scriptable, filterFieldTypes } = this; @@ -121,8 +122,10 @@ export class FieldParamType extends BaseParamType { return false; } - if (!filterFieldTypes) { - return true; + if (isFunction(filterFieldTypes)) { + const filter = filterFieldTypes(aggConfig as IMetricAggConfig); + + return filterByType([field], filter).length !== 0; } return filterByType([field], filterFieldTypes).length !== 0; diff --git a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts index 384c142408012..fb53e72b85c60 100644 --- a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts @@ -20,7 +20,7 @@ import { IndexedArray } from 'ui/indexed_array'; import { AggTypeFieldFilters } from './field_filters'; import { AggConfig } from '../../agg_config'; -import { Field } from '../../../../../../plugins/data/public'; +import { Field } from '../../../../../../../../plugins/data/public'; describe('AggTypeFieldFilters', () => { let registry: AggTypeFieldFilters; diff --git a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/filter/field_filters.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.ts diff --git a/src/legacy/ui/public/agg_types/param_types/filter/index.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/filter/index.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts diff --git a/src/legacy/ui/public/agg_types/param_types/index.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/index.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts diff --git a/src/legacy/ui/public/agg_types/param_types/json.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/json.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/json.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/json.test.ts diff --git a/src/legacy/ui/public/agg_types/param_types/json.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/json.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/json.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/json.ts diff --git a/src/legacy/ui/public/agg_types/param_types/optioned.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/optioned.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.test.ts diff --git a/src/legacy/ui/public/agg_types/param_types/optioned.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/optioned.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.ts diff --git a/src/legacy/ui/public/agg_types/param_types/string.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/string.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/string.test.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/string.test.ts diff --git a/src/legacy/ui/public/agg_types/param_types/string.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/string.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/string.ts rename to src/legacy/core_plugins/data/public/search/aggs/param_types/string.ts diff --git a/src/legacy/ui/public/agg_types/schemas.ts b/src/legacy/core_plugins/data/public/search/aggs/schemas.ts similarity index 98% rename from src/legacy/ui/public/agg_types/schemas.ts rename to src/legacy/core_plugins/data/public/search/aggs/schemas.ts index 05723cac1869d..1aa5ebe08656b 100644 --- a/src/legacy/ui/public/agg_types/schemas.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/schemas.ts @@ -45,7 +45,7 @@ export interface Schema { aggSettings?: any; } -class Schemas { +export class Schemas { // @ts-ignore all: IndexedArray; @@ -103,5 +103,3 @@ class Schemas { .commit(); } } - -export { Schemas }; diff --git a/src/core/server/saved_objects/schema/schema.mock.ts b/src/legacy/core_plugins/data/public/search/aggs/types.ts similarity index 60% rename from src/core/server/saved_objects/schema/schema.mock.ts rename to src/legacy/core_plugins/data/public/search/aggs/types.ts index 89c318f087ab0..2c918abf99fca 100644 --- a/src/core/server/saved_objects/schema/schema.mock.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/types.ts @@ -17,19 +17,13 @@ * under the License. */ -import { SavedObjectsSchema } from './schema'; - -type Schema = PublicMethodsOf; -const createSchemaMock = () => { - const mocked: jest.Mocked = { - getIndexForType: jest.fn().mockReturnValue('.kibana-test'), - isHiddenType: jest.fn().mockReturnValue(false), - isNamespaceAgnostic: jest.fn((type: string) => type === 'global'), - getConvertToAliasScript: jest.fn().mockReturnValue(undefined), - }; - return mocked; -}; - -export const schemaMock = { - create: createSchemaMock, -}; +export { IAggConfig } from './agg_config'; +export { IAggConfigs } from './agg_configs'; +export { IAggType } from './agg_type'; +export { AggParam, AggParamOption } from './agg_params'; +export { IFieldParamType } from './param_types'; +export { IMetricAggType } from './metrics/metric_agg_type'; +export { DateRangeKey } from './buckets/date_range'; +export { IpRangeKey } from './buckets/ip_range'; +export { OptionedValueProp, OptionedParamEditorProps } from './param_types/optioned'; +export { ISchemas } from './schemas'; diff --git a/src/legacy/ui/public/agg_types/utils.test.tsx b/src/legacy/core_plugins/data/public/search/aggs/utils.test.tsx similarity index 100% rename from src/legacy/ui/public/agg_types/utils.test.tsx rename to src/legacy/core_plugins/data/public/search/aggs/utils.test.tsx diff --git a/src/legacy/ui/public/agg_types/utils.ts b/src/legacy/core_plugins/data/public/search/aggs/utils.ts similarity index 92% rename from src/legacy/ui/public/agg_types/utils.ts rename to src/legacy/core_plugins/data/public/search/aggs/utils.ts index e382f821b31a9..62f07ce44ab46 100644 --- a/src/legacy/ui/public/agg_types/utils.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/utils.ts @@ -17,8 +17,8 @@ * under the License. */ -import { isValidEsInterval } from '../../../core_plugins/data/common/parse_es_interval/is_valid_es_interval'; -import { leastCommonInterval } from '../vis/lib/least_common_interval'; +import { leastCommonInterval } from 'ui/vis/lib/least_common_interval'; +import { isValidEsInterval } from '../../../common'; /** * Check a string if it's a valid JSON. diff --git a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts index b4ea2cd378d61..43927337ce574 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts @@ -19,7 +19,7 @@ import { get, has } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { AggConfigs } from 'ui/agg_types/agg_configs'; +import { AggConfigs, IAggConfigs } from 'ui/agg_types'; import { createFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; import { KibanaContext, @@ -50,7 +50,7 @@ import { serializeAggConfig } from './utils'; export interface RequestHandlerParams { searchSource: ISearchSource; - aggs: AggConfigs; + aggs: IAggConfigs; timeRange?: TimeRange; query?: Query; filters?: esFilters.Filter[]; diff --git a/src/legacy/core_plugins/data/public/search/expressions/utils.ts b/src/legacy/core_plugins/data/public/search/expressions/utils.ts index 4f104f2569a98..f0958ba20820f 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/utils.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/utils.ts @@ -17,12 +17,12 @@ * under the License. */ -import { AggConfig } from 'ui/agg_types/agg_config'; -import { AggConfigs } from '../../../../../ui/public/agg_types/agg_configs'; +import { AggConfigs } from '../aggs'; +import { IAggConfig } from '../aggs/types'; import { KibanaDatatableColumnMeta } from '../../../../../../plugins/expressions/common/expression_types'; import { IndexPattern } from '../../../../../../plugins/data/public'; -export const serializeAggConfig = (aggConfig: AggConfig): KibanaDatatableColumnMeta => { +export const serializeAggConfig = (aggConfig: IAggConfig): KibanaDatatableColumnMeta => { return { type: aggConfig.type.name, indexPatternId: aggConfig.getIndexPattern().id, diff --git a/src/legacy/core_plugins/data/public/search/index.ts b/src/legacy/core_plugins/data/public/search/index.ts index c975d5772e0a8..90e191b769a8d 100644 --- a/src/legacy/core_plugins/data/public/search/index.ts +++ b/src/legacy/core_plugins/data/public/search/index.ts @@ -17,5 +17,6 @@ * under the License. */ +export * from './aggs'; export { getRequestInspectorStats, getResponseInspectorStats } from './utils'; export { serializeAggConfig } from './expressions/utils'; diff --git a/src/legacy/core_plugins/data/public/search/search_service.ts b/src/legacy/core_plugins/data/public/search/search_service.ts new file mode 100644 index 0000000000000..45f9ff17328ad --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_service.ts @@ -0,0 +1,93 @@ +/* + * 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 { CoreSetup, CoreStart } from '../../../../../core/public'; +import { + aggTypes, + AggType, + AggConfig, + AggConfigs, + FieldParamType, + MetricAggType, + aggTypeFieldFilters, + setBounds, + parentPipelineAggHelper, + siblingPipelineAggHelper, +} from './aggs'; + +interface AggsSetup { + types: typeof aggTypes; +} + +interface AggsStart { + types: typeof aggTypes; + AggConfig: typeof AggConfig; + AggConfigs: typeof AggConfigs; + AggType: typeof AggType; + aggTypeFieldFilters: typeof aggTypeFieldFilters; + FieldParamType: typeof FieldParamType; + MetricAggType: typeof MetricAggType; + parentPipelineAggHelper: typeof parentPipelineAggHelper; + siblingPipelineAggHelper: typeof siblingPipelineAggHelper; + setBounds: typeof setBounds; +} + +export interface SearchSetup { + aggs: AggsSetup; +} + +export interface SearchStart { + aggs: AggsStart; +} + +/** + * The contract provided here is a new platform shim for ui/agg_types. + * + * Once it has been refactored to work with new platform services, + * it will move into the existing search service in src/plugins/data/public/search + */ +export class SearchService { + public setup(core: CoreSetup): SearchSetup { + return { + aggs: { + types: aggTypes, // TODO convert to registry + // TODO add other items as needed + }, + }; + } + + public start(core: CoreStart): SearchStart { + return { + aggs: { + types: aggTypes, // TODO convert to registry + AggConfig, // TODO make static + AggConfigs, + AggType, + aggTypeFieldFilters, + FieldParamType, + MetricAggType, + parentPipelineAggHelper, // TODO make static + siblingPipelineAggHelper, // TODO make static + setBounds, // TODO make static + }, + }; + } + + public stop() {} +} diff --git a/src/legacy/core_plugins/data/public/search/types.ts b/src/legacy/core_plugins/data/public/search/types.ts index 140ceea487099..47ea1d168f379 100644 --- a/src/legacy/core_plugins/data/public/search/types.ts +++ b/src/legacy/core_plugins/data/public/search/types.ts @@ -17,4 +17,5 @@ * under the License. */ +export * from './aggs/types'; export * from './utils/types'; diff --git a/src/legacy/core_plugins/elasticsearch/server/lib/abortable_request_handler.js b/src/legacy/core_plugins/elasticsearch/server/lib/abortable_request_handler.js index 0b8786f0c2841..68216b92840fc 100644 --- a/src/legacy/core_plugins/elasticsearch/server/lib/abortable_request_handler.js +++ b/src/legacy/core_plugins/elasticsearch/server/lib/abortable_request_handler.js @@ -17,7 +17,7 @@ * under the License. */ -import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill'; +import { AbortController } from 'abort-controller'; /* * A simple utility for generating a handler that provides a signal to the handler that signals when diff --git a/src/legacy/core_plugins/elasticsearch/server/lib/abortable_request_handler.test.js b/src/legacy/core_plugins/elasticsearch/server/lib/abortable_request_handler.test.js index d79dd4ae4e449..1c154370d1674 100644 --- a/src/legacy/core_plugins/elasticsearch/server/lib/abortable_request_handler.test.js +++ b/src/legacy/core_plugins/elasticsearch/server/lib/abortable_request_handler.test.js @@ -17,7 +17,7 @@ * under the License. */ -import { AbortSignal } from 'abortcontroller-polyfill/dist/cjs-ponyfill'; +import { AbortSignal } from 'abort-controller'; import { abortableRequestHandler } from './abortable_request_handler'; describe('abortableRequestHandler', () => { diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js index 8c35044b52c9e..395e0da218307 100644 --- a/src/legacy/core_plugins/kibana/index.js +++ b/src/legacy/core_plugins/kibana/index.js @@ -97,13 +97,8 @@ export default function(kibana) { }), order: -1001, url: `${kbnBaseUrl}#/dashboards`, - // The subUrlBase is the common substring of all urls for this app. If not given, it defaults to the url - // above. This app has to use a different subUrlBase, in addition to the url above, because "#/dashboard" - // routes to a page that creates a new dashboard. When we introduced a landing page, we needed to change - // the url above in order to preserve the original url for BWC. The subUrlBase helps the Chrome api nav - // to determine what url to use for the app link. - subUrlBase: `${kbnBaseUrl}#/dashboard`, euiIconType: 'dashboardApp', + disableSubUrlTracking: true, category: DEFAULT_APP_CATEGORIES.analyze, }, { diff --git a/src/legacy/core_plugins/kibana/public/.eslintrc.js b/src/legacy/core_plugins/kibana/public/.eslintrc.js index 9b45217287dc8..b3ee0a8fa7b04 100644 --- a/src/legacy/core_plugins/kibana/public/.eslintrc.js +++ b/src/legacy/core_plugins/kibana/public/.eslintrc.js @@ -17,8 +17,15 @@ * under the License. */ +const topLevelConfig = require('../../../../../.eslintrc.js'); const path = require('path'); +const topLevelRestricedZones = topLevelConfig.overrides.find( + override => + override.files[0] === '**/*.{js,ts,tsx}' && + Object.keys(override.rules)[0] === '@kbn/eslint/no-restricted-paths' +).rules['@kbn/eslint/no-restricted-paths'][1].zones; + /** * Builds custom restricted paths configuration for the shimmed plugins within the kibana plugin. * These custom rules extend the default checks in the top level `eslintrc.js` by also checking two other things: @@ -28,34 +35,37 @@ const path = require('path'); * @returns zones configuration for the no-restricted-paths linter */ function buildRestrictedPaths(shimmedPlugins) { - return shimmedPlugins.map(shimmedPlugin => ([{ - target: [ - `src/legacy/core_plugins/kibana/public/${shimmedPlugin}/np_ready/**/*`, - ], - from: [ - 'ui/**/*', - 'src/legacy/ui/**/*', - 'src/legacy/core_plugins/kibana/public/**/*', - 'src/legacy/core_plugins/data/public/**/*', - '!src/legacy/core_plugins/data/public/index.ts', - `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`, - ], - allowSameFolder: false, - errorMessage: `${shimmedPlugin} is a shimmed plugin that is not allowed to import modules from the legacy platform. If you need legacy modules for the transition period, import them either in the legacy_imports, kibana_services or index module.`, - }, { - target: [ - 'src/**/*', - `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`, - 'x-pack/**/*', - ], - from: [ - `src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`, - `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/index.ts`, - `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/legacy.ts`, - ], - allowSameFolder: false, - errorMessage: `kibana/public/${shimmedPlugin} is behaving like a NP plugin and does not allow deep imports. If you need something from within ${shimmedPlugin} in another plugin, consider re-exporting it from the top level index module`, - }])).reduce((acc, part) => [...acc, ...part], []); + return shimmedPlugins + .map(shimmedPlugin => [ + { + target: [`src/legacy/core_plugins/kibana/public/${shimmedPlugin}/np_ready/**/*`], + from: [ + 'ui/**/*', + 'src/legacy/ui/**/*', + 'src/legacy/core_plugins/kibana/public/**/*', + 'src/legacy/core_plugins/data/public/**/*', + '!src/legacy/core_plugins/data/public/index.ts', + `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`, + ], + allowSameFolder: false, + errorMessage: `${shimmedPlugin} is a shimmed plugin that is not allowed to import modules from the legacy platform. If you need legacy modules for the transition period, import them either in the legacy_imports, kibana_services or index module.`, + }, + { + target: [ + 'src/**/*', + `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`, + 'x-pack/**/*', + ], + from: [ + `src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`, + `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/index.ts`, + `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/legacy.ts`, + ], + allowSameFolder: false, + errorMessage: `kibana/public/${shimmedPlugin} is behaving like a NP plugin and does not allow deep imports. If you need something from within ${shimmedPlugin} in another plugin, consider re-exporting it from the top level index module`, + }, + ]) + .reduce((acc, part) => [...acc, ...part], []); } module.exports = { @@ -66,7 +76,9 @@ module.exports = { 'error', { basePath: path.resolve(__dirname, '../../../../../'), - zones: buildRestrictedPaths(['visualize', 'discover', 'dashboard', 'devTools', 'home']), + zones: topLevelRestricedZones.concat( + buildRestrictedPaths(['visualize', 'discover', 'dashboard', 'devTools', 'home']) + ), }, ], }, diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy.ts index acbc4c4b6c47f..ca2dc9d5fb4f5 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/legacy.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy.ts @@ -41,6 +41,7 @@ async function getAngularDependencies(): Promise {}, + warn: () => {}, debug: () => {}, info: () => {}, }; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts index f1fd93fd09b3d..b0e4785edcb0b 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts @@ -73,7 +73,6 @@ export const renderApp = (element: HTMLElement, appBasePath: string, deps: Rende angularModuleInstance = createLocalAngularModule(deps.core, deps.navigation); // global routing stuff configureAppAngularModule(angularModuleInstance, deps.core as LegacyCoreStart, true); - // custom routing stuff initDashboardApp(angularModuleInstance, deps); } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index 624be02ac3b9d..9f6b01d5beb49 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -31,8 +31,6 @@ import { ConfirmationButtonTypes, migrateLegacyQuery, SavedObjectSaveOpts, - SaveResult, - showSaveModal, subscribeWithScope, } from '../legacy_imports'; import { @@ -45,6 +43,11 @@ import { syncAppFilters, syncQuery, } from '../../../../../../plugins/data/public'; +import { + SaveResult, + showSaveModal, + getSavedObjectFinder, +} from '../../../../../../plugins/saved_objects/public'; import { DASHBOARD_CONTAINER_TYPE, @@ -74,10 +77,6 @@ import { getDashboardTitle } from './dashboard_strings'; import { DashboardAppScope } from './dashboard_app'; import { convertSavedDashboardPanelToPanelState } from './lib/embeddable_saved_object_converters'; import { RenderDeps } from './application'; -import { - SavedObjectFinderProps, - SavedObjectFinderUi, -} from '../../../../../../plugins/kibana_react/public'; import { IKbnUrlStateStorage, removeQueryParam, @@ -114,7 +113,16 @@ export class DashboardAppController { share, dashboardCapabilities, npDataStart: { query: queryService }, - core: { notifications, overlays, chrome, injectedMetadata, uiSettings, savedObjects, http }, + core: { + notifications, + overlays, + chrome, + injectedMetadata, + uiSettings, + savedObjects, + http, + i18n: i18nStart, + }, history, kbnUrlStateStorage, }: DashboardAppControllerDependencies) { @@ -777,7 +785,7 @@ export class DashboardAppController { showCopyOnSave={dash.id ? true : false} /> ); - showSaveModal(dashboardSaveModal); + showSaveModal(dashboardSaveModal, i18nStart.Context); }; navActions[TopNavIds.CLONE] = () => { const currentTitle = dashboardStateManager.getTitle(); @@ -806,17 +814,13 @@ export class DashboardAppController { }; navActions[TopNavIds.ADD] = () => { if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) { - const SavedObjectFinder = (props: SavedObjectFinderProps) => ( - - ); - openAddPanelFlyout({ embeddable: dashboardContainer, getAllFactories: embeddables.getEmbeddableFactories, getFactory: embeddables.getEmbeddableFactory, notifications, overlays, - SavedObjectFinder, + SavedObjectFinder: getSavedObjectFinder(savedObjects, uiSettings), }); } }; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/test_utils/get_saved_dashboard_mock.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/test_utils/get_saved_dashboard_mock.ts index d5e61936f67cf..60b2a33f720ec 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/test_utils/get_saved_dashboard_mock.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/test_utils/get_saved_dashboard_mock.ts @@ -17,7 +17,7 @@ * under the License. */ -import { searchSourceMock } from '../../../../../../../plugins/data/public/search/search_source/mocks'; +import { searchSourceMock } from '../../../../../../../plugins/data/public/mocks'; import { SavedObjectDashboard } from '../../saved_dashboard/saved_dashboard'; export function getSavedDashboardMock( diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/save_modal.test.js b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/save_modal.test.js index 5f708a22fd530..e3933ce9d0143 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/save_modal.test.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/save_modal.test.js @@ -20,7 +20,7 @@ import React from 'react'; import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers'; -jest.mock('../../legacy_imports', () => ({ +jest.mock('../../../../../../../plugins/saved_objects/public', () => ({ SavedObjectSaveModal: () => null, })); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/save_modal.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/save_modal.tsx index bd53fd5a13083..026784fcae06f 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/save_modal.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/top_nav/save_modal.tsx @@ -21,7 +21,7 @@ import React, { Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFormRow, EuiTextArea, EuiSwitch } from '@elastic/eui'; -import { SavedObjectSaveModal } from '../../legacy_imports'; +import { SavedObjectSaveModal } from '../../../../../../../plugins/saved_objects/public'; interface SaveOptions { newTitle: string; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts index 227bcb53ca0df..7ae1c723a3914 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts @@ -17,6 +17,7 @@ * under the License. */ +import { BehaviorSubject } from 'rxjs'; import { App, CoreSetup, @@ -28,7 +29,10 @@ import { import { i18n } from '@kbn/i18n'; import { RenderDeps } from './np_ready/application'; import { DataStart } from '../../../data/public'; -import { DataPublicPluginStart as NpDataStart } from '../../../../../plugins/data/public'; +import { + DataPublicPluginStart as NpDataStart, + DataPublicPluginSetup as NpDataSetup, +} from '../../../../../plugins/data/public'; import { IEmbeddableStart } from '../../../../../plugins/embeddable/public'; import { Storage } from '../../../../../plugins/kibana_utils/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; @@ -38,8 +42,13 @@ import { HomePublicPluginSetup, } from '../../../../../plugins/home/public'; import { SharePluginStart } from '../../../../../plugins/share/public'; -import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public'; +import { + AngularRenderedAppUpdater, + KibanaLegacySetup, +} from '../../../../../plugins/kibana_legacy/public'; import { createSavedDashboardLoader } from './saved_dashboard/saved_dashboards'; +import { createKbnUrlTracker } from '../../../../../plugins/kibana_utils/public'; +import { getQueryStateContainer } from '../../../../../plugins/data/public'; export interface LegacyAngularInjectedDependencies { dashboardConfig: any; @@ -58,7 +67,8 @@ export interface DashboardPluginSetupDependencies { getAngularDependencies: () => Promise; }; home: HomePublicPluginSetup; - kibana_legacy: KibanaLegacySetup; + kibanaLegacy: KibanaLegacySetup; + npData: NpDataSetup; } export class DashboardPlugin implements Plugin { @@ -70,10 +80,38 @@ export class DashboardPlugin implements Plugin { share: SharePluginStart; } | null = null; + private appStateUpdater = new BehaviorSubject(() => ({})); + private stopUrlTracking: (() => void) | undefined = undefined; + public setup( core: CoreSetup, - { __LEGACY: { getAngularDependencies }, home, kibana_legacy }: DashboardPluginSetupDependencies + { + __LEGACY: { getAngularDependencies }, + home, + kibanaLegacy, + npData, + }: DashboardPluginSetupDependencies ) { + const { querySyncStateContainer, stop: stopQuerySyncStateContainer } = getQueryStateContainer( + npData.query + ); + const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({ + baseUrl: core.http.basePath.prepend('/app/kibana'), + defaultSubUrl: '#/dashboards', + storageKey: 'lastUrl:dashboard', + navLinkUpdater$: this.appStateUpdater, + toastNotifications: core.notifications.toasts, + stateParams: [ + { + kbnUrlKey: '_g', + stateUpdate$: querySyncStateContainer.state$, + }, + ], + }); + this.stopUrlTracking = () => { + stopQuerySyncStateContainer(); + stopUrlTracker(); + }; const app: App = { id: '', title: 'Dashboards', @@ -81,6 +119,7 @@ export class DashboardPlugin implements Plugin { if (this.startDependencies === null) { throw new Error('not started yet'); } + appMounted(); const { savedObjectsClient, embeddables, @@ -107,18 +146,28 @@ export class DashboardPlugin implements Plugin { chrome: contextCore.chrome, addBasePath: contextCore.http.basePath.prepend, uiSettings: contextCore.uiSettings, - config: kibana_legacy.config, + config: kibanaLegacy.config, savedQueryService: npDataStart.query.savedQueries, embeddables, dashboardCapabilities: contextCore.application.capabilities.dashboard, localStorage: new Storage(localStorage), }; const { renderApp } = await import('./np_ready/application'); - return renderApp(params.element, params.appBasePath, deps); + const unmount = renderApp(params.element, params.appBasePath, deps); + return () => { + unmount(); + appUnMounted(); + }; }, }; - kibana_legacy.registerLegacyApp({ ...app, id: 'dashboard' }); - kibana_legacy.registerLegacyApp({ ...app, id: 'dashboards' }); + kibanaLegacy.registerLegacyApp({ + ...app, + id: 'dashboard', + // only register the updater in once app, otherwise all updates would happen twice + updater$: this.appStateUpdater.asObservable(), + navLinkId: 'kibana:dashboard', + }); + kibanaLegacy.registerLegacyApp({ ...app, id: 'dashboards' }); home.featureCatalogue.register({ id: 'dashboard', @@ -147,4 +196,10 @@ export class DashboardPlugin implements Plugin { share, }; } + + stop() { + if (this.stopUrlTracking) { + this.stopUrlTracking(); + } + } } diff --git a/src/legacy/core_plugins/kibana/public/dev_tools/index.ts b/src/legacy/core_plugins/kibana/public/dev_tools/index.ts index f2555259028cc..6515674c6b52a 100644 --- a/src/legacy/core_plugins/kibana/public/dev_tools/index.ts +++ b/src/legacy/core_plugins/kibana/public/dev_tools/index.ts @@ -22,7 +22,7 @@ import 'uiExports/devTools'; import { npStart } from 'ui/new_platform'; -if (npStart.plugins.dev_tools.getSortedDevTools().length === 0) { +if (npStart.plugins.devTools.getSortedDevTools().length === 0) { npStart.core.chrome.navLinks.update('kibana:dev_tools', { hidden: true, }); diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index d1e1dafe7c878..820c9949342a4 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -55,11 +55,9 @@ export { buildVislibDimensions } from '../../../visualizations/public'; export { callAfterBindingsWorkaround } from 'ui/compat'; export { getRequestInspectorStats, getResponseInspectorStats } from '../../../data/public'; // @ts-ignore -export { intervalOptions } from 'ui/agg_types/buckets/_interval_options'; +export { intervalOptions } from 'ui/agg_types'; // @ts-ignore export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; -export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal'; -export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal'; export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory'; export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; // @ts-ignore diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.html b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.html index 3e0f8a8329154..8bbb746fa45f8 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.html +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.html @@ -2,12 +2,11 @@ app-name="'context'" show-search-bar="true" show-filter-bar="true" + show-query-bar="false" show-save-query="false" show-date-picker="false" - - filters="contextApp.state.queryParameters.filters" - on-filters-updated="contextApp.actions.updateFilters" index-patterns="[contextApp.indexPattern]" + use-default-behaviors="true" > diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.js index 5fa0958249d79..6549f13556373 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import { getServices, callAfterBindingsWorkaround, getAngularModule } from '../../kibana_services'; +import { callAfterBindingsWorkaround, getAngularModule } from '../../kibana_services'; import contextAppTemplate from './context_app.html'; import './context/components/action_bar'; import { getFirstSortableField } from './context/api/utils/sorting'; @@ -34,8 +34,6 @@ import { QueryActionsProvider, } from './context/query'; -const { timefilter } = getServices(); - const module = getAngularModule(); module.directive('contextApp', function ContextApp() { @@ -61,10 +59,6 @@ module.directive('contextApp', function ContextApp() { function ContextAppController($scope, config, Private) { const queryParameterActions = getQueryParameterActions(); const queryActions = Private(QueryActionsProvider); - - timefilter.disableAutoRefreshSelector(); - timefilter.disableTimeRangeSelector(); - this.state = createInitialState( parseInt(config.get('context:step'), 10), getFirstSortableField(this.indexPattern, config.get('context:tieBreakerFields')), diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx index 4d387f44c3d57..77bbab97d95c7 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx @@ -30,7 +30,6 @@ import { Axis, Chart, HistogramBarSeries, - GeometryValue, LineAnnotation, Position, ScaleType, @@ -38,6 +37,7 @@ import { RectAnnotation, TooltipValue, TooltipType, + ElementClickListener, } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; @@ -139,7 +139,7 @@ export class DiscoverHistogram extends Component (elementData: GeometryValue[]) => { + public onElementClick = (xInterval: number): ElementClickListener => ([elementData]) => { const startRange = elementData[0].x; const range = { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html index 45490ac7adc0f..efde83a0e35f0 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html @@ -5,24 +5,19 @@

{{screenTitle}}

diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index 2f73af2ab77e4..69f69d449354c 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -19,13 +19,18 @@ import _ from 'lodash'; import React from 'react'; -import { Subscription } from 'rxjs'; +import { Subscription, Subject, merge } from 'rxjs'; +import { debounceTime } from 'rxjs/operators'; import moment from 'moment'; import dateMath from '@elastic/datemath'; import { i18n } from '@kbn/i18n'; import '../components/field_chooser/field_chooser'; import { RequestAdapter } from '../../../../../../../plugins/inspector/public'; +import { + SavedObjectSaveModal, + showSaveModal, +} from '../../../../../../../plugins/saved_objects/public'; // doc table import './doc_table'; import { getSortArray } from './doc_table/lib/get_sort'; @@ -47,12 +52,10 @@ import { hasSearchStategyForIndexPattern, intervalOptions, migrateLegacyQuery, - showSaveModal, unhashUrl, stateMonitorFactory, subscribeWithScope, tabifyAggResponse, - SavedObjectSaveModal, getAngularModule, ensureDefaultIndexPattern, registerTimefilterWithGlobalStateFactory, @@ -62,7 +65,6 @@ import { Vis } from '../../../../../visualizations/public'; const { core, chrome, - data, docTitle, filterManager, share, @@ -79,8 +81,6 @@ import { import { getIndexPatternId } from '../helpers/get_index_pattern_id'; import { FilterStateManager } from '../../../../../data/public'; -const { getSavedQuery } = data.query.savedQueries; - const fetchStatuses = { UNINITIALIZED: 'uninitialized', LOADING: 'loading', @@ -205,8 +205,6 @@ function discoverController( const subscriptions = new Subscription(); - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); $scope.timefilterUpdateHandler = ranges => { timefilter.setTime({ from: moment(ranges.from).toISOString(), @@ -218,7 +216,6 @@ function discoverController( $scope.showInterval = false; $scope.minimumVisibleRows = 50; $scope.fetchStatus = fetchStatuses.UNINITIALIZED; - $scope.refreshInterval = timefilter.getRefreshInterval(); $scope.showSaveQuery = uiCapabilities.discover.saveQuery; $scope.$watch( @@ -310,7 +307,7 @@ function discoverController( })} /> ); - showSaveModal(saveModal); + showSaveModal(saveModal, core.i18n.Context); }, }; @@ -436,15 +433,10 @@ function discoverController( let stateMonitor; const $state = ($scope.state = new AppState(getStateDefaults())); + const $fetchObservable = new Subject(); - $scope.filters = filterManager.getFilters(); $scope.screenTitle = savedSearch.title; - $scope.onFiltersUpdated = filters => { - // The filters will automatically be set when the filterManager emits an update event (see below) - filterManager.setFilters(filters); - }; - const getFieldCounts = async () => { // the field counts aren't set until we have the data back, // so we wait for the fetch to be done before proceeding @@ -571,17 +563,12 @@ function discoverController( }; const shouldSearchOnPageLoad = () => { - // If a saved query is referenced in the app state, omit the initial load because the saved query will - // be fetched separately and trigger a reload - if ($scope.state.savedQuery) { - return false; - } // A saved search is created on every page load, so we check the ID to see if we're loading a // previously saved search or if it is just transient return ( config.get('discover:searchOnPageLoad') || savedSearch.id !== undefined || - _.get($scope, 'refreshInterval.pause') === false + timefilter.getRefreshInterval().pause === false ); }; @@ -593,25 +580,23 @@ function discoverController( $scope.$on('$destroy', () => stateMonitor.destroy()); $scope.updateDataSource().then(function() { - subscriptions.add( - subscribeWithScope($scope, timefilter.getAutoRefreshFetch$(), { - next: $scope.fetch, - }) - ); + const searchBarChanges = merge( + timefilter.getAutoRefreshFetch$(), + timefilter.getFetch$(), + filterManager.getFetches$(), + $fetchObservable + ).pipe(debounceTime(100)); subscriptions.add( - subscribeWithScope($scope, timefilter.getRefreshIntervalUpdate$(), { - next: $scope.updateRefreshInterval, + subscribeWithScope($scope, searchBarChanges, { + next: $scope.fetch, }) ); subscriptions.add( subscribeWithScope($scope, timefilter.getTimeUpdate$(), { - next: $scope.updateTime, - }) - ); - subscriptions.add( - subscribeWithScope($scope, timefilter.getFetch$(), { - next: $scope.fetch, + next: () => { + $scope.updateTime(); + }, }) ); @@ -622,14 +607,14 @@ function discoverController( const currentSort = getSortArray($scope.searchSource.getField('sort'), $scope.indexPattern); // if the searchSource doesn't know, tell it so - if (!angular.equals(sort, currentSort)) $scope.fetch(); + if (!angular.equals(sort, currentSort)) $fetchObservable.next(); }); // update data source when filters update + subscriptions.add( subscribeWithScope($scope, filterManager.getUpdates$(), { next: () => { - $scope.filters = filterManager.getFilters(); $scope.updateDataSource().then(function() { $state.save(); }); @@ -637,16 +622,9 @@ function discoverController( }) ); - // fetch data when filters fire fetch event - subscriptions.add( - subscribeWithScope($scope, filterManager.getFetches$(), { - next: $scope.fetch, - }) - ); - // update data source when hitting forward/back and the query changes $scope.$listen($state, 'fetch_with_changes', function(diff) { - if (diff.indexOf('query') >= 0) $scope.fetch(); + if (diff.indexOf('query') >= 0) $fetchObservable.next(); }); $scope.$watch('opts.timefield', function(timefield) { @@ -655,7 +633,7 @@ function discoverController( $scope.$watch('state.interval', function(newInterval, oldInterval) { if (newInterval !== oldInterval) { - $scope.fetch(); + $fetchObservable.next(); } }); @@ -674,7 +652,7 @@ function discoverController( if (!_.isEqual(newQuery, oldQuery)) { const query = migrateLegacyQuery(newQuery); if (!_.isEqual(query, newQuery)) { - $scope.updateQueryAndFetch({ query }); + $scope.updateQuery({ query }); } } }); @@ -734,7 +712,7 @@ function discoverController( $state.replace(); if (shouldSearchOnPageLoad()) { - $scope.fetch(); + $fetchObservable.next(); } }); }); @@ -827,15 +805,9 @@ function discoverController( }); }; - $scope.updateQueryAndFetch = function({ query, dateRange }) { - const oldDateRange = timefilter.getTime(); - timefilter.setTime(dateRange); + $scope.updateQuery = function({ query }) { $state.query = query; - // storing the updated timerange in the state will trigger a fetch - // call automatically, so only trigger fetch in case this is a refresh call (no changes in parameters). - if (_.isEqual(oldDateRange, dateRange)) { - $scope.fetch(); - } + $fetchObservable.next(); }; function onResults(resp) { @@ -896,32 +868,12 @@ function discoverController( from: dateMath.parse(timefilter.getTime().from), to: dateMath.parse(timefilter.getTime().to, { roundUp: true }), }; - $scope.time = timefilter.getTime(); }; $scope.toMoment = function(datetime) { return moment(datetime).format(config.get('dateFormat')); }; - $scope.updateRefreshInterval = function() { - const newInterval = timefilter.getRefreshInterval(); - const shouldFetch = - _.get($scope, 'refreshInterval.pause') === true && newInterval.pause === false; - - $scope.refreshInterval = newInterval; - - if (shouldFetch) { - $scope.fetch(); - } - }; - - $scope.onRefreshChange = function({ isPaused, refreshInterval }) { - timefilter.setRefreshInterval({ - pause: isPaused, - value: refreshInterval ? refreshInterval : $scope.refreshInterval.value, - }); - }; - $scope.resetQuery = function() { kbnUrl.change('/discover/{{id}}', { id: $route.current.params.id }); }; @@ -988,69 +940,14 @@ function discoverController( $scope.minimumVisibleRows = $scope.hits; }; - $scope.onQuerySaved = savedQuery => { - $scope.savedQuery = savedQuery; - }; - - $scope.onSavedQueryUpdated = savedQuery => { - $scope.savedQuery = { ...savedQuery }; - }; - - $scope.onClearSavedQuery = () => { - delete $scope.savedQuery; - delete $state.savedQuery; - $state.query = { - query: '', - language: localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage'), - }; - filterManager.setFilters(filterManager.getGlobalFilters()); - $state.save(); - $scope.fetch(); - }; - - const updateStateFromSavedQuery = savedQuery => { - $state.query = savedQuery.attributes.query; - $state.save(); - const savedQueryFilters = savedQuery.attributes.filters || []; - const globalFilters = filterManager.getGlobalFilters(); - filterManager.setFilters([...globalFilters, ...savedQueryFilters]); - - if (savedQuery.attributes.timefilter) { - timefilter.setTime({ - from: savedQuery.attributes.timefilter.from, - to: savedQuery.attributes.timefilter.to, - }); - if (savedQuery.attributes.timefilter.refreshInterval) { - timefilter.setRefreshInterval(savedQuery.attributes.timefilter.refreshInterval); - } + $scope.updateSavedQueryId = newSavedQueryId => { + if (newSavedQueryId) { + $state.savedQuery = newSavedQueryId; + } else { + delete $state.savedQuery; } - - $scope.fetch(); - }; - - $scope.$watch('savedQuery', newSavedQuery => { - if (!newSavedQuery) return; - - $state.savedQuery = newSavedQuery.id; $state.save(); - - updateStateFromSavedQuery(newSavedQuery); - }); - - $scope.$watch('state.savedQuery', newSavedQueryId => { - if (!newSavedQueryId) { - $scope.savedQuery = undefined; - return; - } - if (!$scope.savedQuery || newSavedQueryId !== $scope.savedQuery.id) { - getSavedQuery(newSavedQueryId).then(savedQuery => { - $scope.$evalAsync(() => { - $scope.savedQuery = savedQuery; - updateStateFromSavedQuery(savedQuery); - }); - }); - } - }); + }; async function setupVisualization() { // If no timefield has been specified we don't create a histogram of messages diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/doc/use_es_doc_search.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/doc/use_es_doc_search.ts index d3bf3696c08a5..6cffc2cc533b0 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/doc/use_es_doc_search.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/doc/use_es_doc_search.ts @@ -62,36 +62,34 @@ export function useEsDocSearch({ const [status, setStatus] = useState(ElasticRequestState.Loading); const [hit, setHit] = useState(null); - async function requestData() { - try { - const indexPatternEntity = await indexPatternService.get(indexPatternId); - setIndexPattern(indexPatternEntity); + useEffect(() => { + async function requestData() { + try { + const indexPatternEntity = await indexPatternService.get(indexPatternId); + setIndexPattern(indexPatternEntity); - const { hits } = await esClient.search({ - index, - body: buildSearchBody(id, indexPatternEntity), - }); + const { hits } = await esClient.search({ + index, + body: buildSearchBody(id, indexPatternEntity), + }); - if (hits && hits.hits && hits.hits[0]) { - setStatus(ElasticRequestState.Found); - setHit(hits.hits[0]); - } else { - setStatus(ElasticRequestState.NotFound); - } - } catch (err) { - if (err.savedObjectId) { - setStatus(ElasticRequestState.NotFoundIndexPattern); - } else if (err.status === 404) { - setStatus(ElasticRequestState.NotFound); - } else { - setStatus(ElasticRequestState.Error); + if (hits && hits.hits && hits.hits[0]) { + setStatus(ElasticRequestState.Found); + setHit(hits.hits[0]); + } else { + setStatus(ElasticRequestState.NotFound); + } + } catch (err) { + if (err.savedObjectId) { + setStatus(ElasticRequestState.NotFoundIndexPattern); + } else if (err.status === 404) { + setStatus(ElasticRequestState.NotFound); + } else { + setStatus(ElasticRequestState.Error); + } } } - } - - useEffect(() => { requestData(); - }); - + }, [esClient, id, index, indexPatternId, indexPatternService]); return [status, hit, indexPattern]; } diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/top_nav/open_search_panel.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/top_nav/open_search_panel.js index ebe4cbb1ddb69..747dd9abe2f2a 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/top_nav/open_search_panel.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/top_nav/open_search_panel.js @@ -32,7 +32,7 @@ import { EuiFlyoutBody, EuiTitle, } from '@elastic/eui'; -import { SavedObjectFinderUi } from '../../../../../../../../plugins/kibana_react/public'; +import { SavedObjectFinderUi } from '../../../../../../../../plugins/saved_objects/public'; import { getServices } from '../../../kibana_services'; const SEARCH_OBJECT_TYPE = 'search'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts index f47cf52c756ac..3f877520b5bf9 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts @@ -20,7 +20,7 @@ import _ from 'lodash'; import * as Rx from 'rxjs'; import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; -import { TExecuteTriggerActions } from 'src/plugins/ui_actions/public'; +import { ExecuteTriggerActions } from 'src/plugins/ui_actions/public'; import { RequestAdapter, Adapters } from '../../../../../../../plugins/inspector/public'; import { esFilters, @@ -111,7 +111,7 @@ export class SearchEmbeddable extends Embeddable filterManager, }: SearchEmbeddableConfig, initialInput: SearchInput, - private readonly executeTriggerActions: TExecuteTriggerActions, + private readonly executeTriggerActions: ExecuteTriggerActions, parent?: Container ) { super( diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable_factory.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable_factory.ts index 842ef2bf9c825..15b3f2d4517ac 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable_factory.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable_factory.ts @@ -19,7 +19,7 @@ import { auto } from 'angular'; import { i18n } from '@kbn/i18n'; -import { TExecuteTriggerActions } from 'src/plugins/ui_actions/public'; +import { ExecuteTriggerActions } from 'src/plugins/ui_actions/public'; import { getServices } from '../../kibana_services'; import { EmbeddableFactory, @@ -43,7 +43,7 @@ export class SearchEmbeddableFactory extends EmbeddableFactory< public isEditable: () => boolean; constructor( - private readonly executeTriggerActions: TExecuteTriggerActions, + private readonly executeTriggerActions: ExecuteTriggerActions, getInjector: () => Promise, isEditable: () => boolean ) { diff --git a/src/legacy/core_plugins/kibana/public/discover/plugin.ts b/src/legacy/core_plugins/kibana/public/discover/plugin.ts index 77135f6a98173..a495b56d5e9ea 100644 --- a/src/legacy/core_plugins/kibana/public/discover/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/discover/plugin.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { AppMountParameters, CoreSetup, CoreStart, Plugin } from 'kibana/public'; import angular, { auto } from 'angular'; -import { IUiActionsSetup, IUiActionsStart } from 'src/plugins/ui_actions/public'; +import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { registerFeature } from './np_ready/register_feature'; import './kibana_services'; @@ -47,13 +47,13 @@ export interface DiscoverSetup { } export type DiscoverStart = void; export interface DiscoverSetupPlugins { - uiActions: IUiActionsSetup; + uiActions: UiActionsSetup; embeddable: IEmbeddableSetup; - kibana_legacy: KibanaLegacySetup; + kibanaLegacy: KibanaLegacySetup; home: HomePublicPluginSetup; } export interface DiscoverStartPlugins { - uiActions: IUiActionsStart; + uiActions: UiActionsStart; embeddable: IEmbeddableStart; navigation: NavigationStart; charts: ChartsPluginStart; @@ -99,7 +99,7 @@ export class DiscoverPlugin implements Plugin { order: 20, component: JsonCodeBlock, }); - plugins.kibana_legacy.registerLegacyApp({ + plugins.kibanaLegacy.registerLegacyApp({ id: 'discover', title: 'Discover', order: -1004, diff --git a/src/legacy/core_plugins/kibana/public/home/np_ready/components/tutorial/instruction_set.js b/src/legacy/core_plugins/kibana/public/home/np_ready/components/tutorial/instruction_set.js index 15bda33534185..631ef1d6e0e42 100644 --- a/src/legacy/core_plugins/kibana/public/home/np_ready/components/tutorial/instruction_set.js +++ b/src/legacy/core_plugins/kibana/public/home/np_ready/components/tutorial/instruction_set.js @@ -22,7 +22,7 @@ import PropTypes from 'prop-types'; import { Instruction } from './instruction'; import { ParameterForm } from './parameter_form'; import { Content } from './content'; -import { getDisplayText } from '../../../../../../../../plugins/home/server/tutorials/instructions/instruction_variant'; +import { getDisplayText } from '../../../../../../../../plugins/home/public'; import { EuiTabs, EuiTab, diff --git a/src/legacy/core_plugins/kibana/public/home/plugin.ts b/src/legacy/core_plugins/kibana/public/home/plugin.ts index aec3835dc075d..5802f33627fb3 100644 --- a/src/legacy/core_plugins/kibana/public/home/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/home/plugin.ts @@ -59,7 +59,7 @@ export interface HomePluginSetupDependencies { getAngularDependencies: () => Promise; }; usageCollection: UsageCollectionSetup; - kibana_legacy: KibanaLegacySetup; + kibanaLegacy: KibanaLegacySetup; home: HomePublicPluginSetup; } @@ -72,12 +72,12 @@ export class HomePlugin implements Plugin { core: CoreSetup, { home, - kibana_legacy, + kibanaLegacy, usageCollection, __LEGACY: { getAngularDependencies, ...legacyServices }, }: HomePluginSetupDependencies ) { - kibana_legacy.registerLegacyApp({ + kibanaLegacy.registerLegacyApp({ id: 'home', title: 'Home', mount: async ({ core: contextCore }, params) => { @@ -98,7 +98,7 @@ export class HomePlugin implements Plugin { getBasePath: core.http.basePath.get, indexPatternService: this.dataStart!.indexPatterns, environment: this.environment!, - config: kibana_legacy.config, + config: kibanaLegacy.config, homeConfig: home.config, ...angularDependencies, }); diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js index f2868da947a75..d77fc780f4cc2 100644 --- a/src/legacy/core_plugins/kibana/public/kibana.js +++ b/src/legacy/core_plugins/kibana/public/kibana.js @@ -57,13 +57,13 @@ import { showAppRedirectNotification } from 'ui/notify'; import 'leaflet'; import { localApplicationService } from './local_application_service'; -npSetup.plugins.kibana_legacy.forwardApp('doc', 'discover', { keepPrefix: true }); -npSetup.plugins.kibana_legacy.forwardApp('context', 'discover', { keepPrefix: true }); +npSetup.plugins.kibanaLegacy.forwardApp('doc', 'discover', { keepPrefix: true }); +npSetup.plugins.kibanaLegacy.forwardApp('context', 'discover', { keepPrefix: true }); localApplicationService.attachToAngular(routes); routes.enable(); -const { config } = npSetup.plugins.kibana_legacy; +const { config } = npSetup.plugins.kibanaLegacy; routes.otherwise({ redirectTo: `/${config.defaultAppId || 'discover'}`, }); diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts index d52bec8304ff9..90328003c8292 100644 --- a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts +++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts @@ -50,7 +50,7 @@ export class LocalApplicationService { * @param angularRouteManager The current `ui/routes` instance */ attachToAngular(angularRouteManager: UIRoutes) { - npStart.plugins.kibana_legacy.getApps().forEach(app => { + npStart.plugins.kibanaLegacy.getApps().forEach(app => { const wrapperElementId = this.idGenerator(); angularRouteManager.when(matchAllWithPrefix(app), { outerAngularWrapperRoute: true, @@ -79,9 +79,20 @@ export class LocalApplicationService { })(); }, }); + + if (app.updater$) { + app.updater$.subscribe(updater => { + const updatedFields = updater(app); + if (updatedFields && updatedFields.activeUrl) { + npStart.core.chrome.navLinks.update(app.navLinkId || app.id, { + url: updatedFields.activeUrl, + }); + } + }); + } }); - npStart.plugins.kibana_legacy.getForwards().forEach(({ legacyAppId, newAppId, keepPrefix }) => { + npStart.plugins.kibanaLegacy.getForwards().forEach(({ legacyAppId, newAppId, keepPrefix }) => { angularRouteManager.when(matchAllWithPrefix(legacyAppId), { resolveRedirectTo: ($location: ILocationService) => { const url = $location.url(); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.js index c990efaf43547..e10f033ed8165 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.js @@ -279,13 +279,12 @@ export class StepIndexPattern extends Component { render() { const { isIncludingSystemIndices, allIndices } = this.props; - const { query, partialMatchedIndices, exactMatchedIndices } = this.state; + const { partialMatchedIndices, exactMatchedIndices } = this.state; const matchedIndices = getMatchedIndices( allIndices, partialMatchedIndices, exactMatchedIndices, - query, isIncludingSystemIndices ); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/constants/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/constants/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/constants/index.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/constants/index.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.error.json b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.error.json deleted file mode 100644 index acb9a9ecd0206..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.error.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "statusCode": 400, - "error": "Bad Request" -} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.exception.json b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.exception.json deleted file mode 100644 index 1406b06813637..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.exception.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "body": { - "error": { - "root_cause": [ - { - "type": "index_not_found_exception", - "reason": "no such index", - "index_uuid": "_na_", - "resource.type": "index_or_alias", - "resource.id": "t", - "index": "t" - } - ], - "type": "transport_exception", - "reason": "unable to communicate with remote cluster [cluster_one]", - "caused_by": { - "type": "index_not_found_exception", - "reason": "no such index", - "index_uuid": "_na_", - "resource.type": "index_or_alias", - "resource.id": "t", - "index": "t" - } - } - }, - "status": 500 -} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.success.json b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.success.json deleted file mode 100644 index 1b261243ca728..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/api/get_indices.success.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "hits": { - "total": 1, - "max_score": 0.0, - "hits": [] - }, - "aggregations": { - "indices": { - "doc_count_error_upper_bound": 0, - "sum_other_doc_count": 0, - "buckets": [{ - "key": "1", - "doc_count": 1 - },{ - "key": "2", - "doc_count": 1 - }] - } - } -} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/get_indices.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/get_indices.test.js deleted file mode 100644 index 924b0dc46d74d..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/get_indices.test.js +++ /dev/null @@ -1,117 +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 { getIndices } from '../get_indices'; -import successfulResponse from './api/get_indices.success.json'; -import errorResponse from './api/get_indices.error.json'; -import exceptionResponse from './api/get_indices.exception.json'; -const mockIndexPatternCreationType = { - getIndexPatternType: () => 'default', - getIndexPatternName: () => 'name', - checkIndicesForErrors: () => false, - getShowSystemIndices: () => false, - renderPrompt: () => {}, - getIndexPatternMappings: () => { - return {}; - }, - getIndexTags: () => { - return []; - }, -}; - -describe('getIndices', () => { - it('should work in a basic case', async () => { - const es = { - search: () => new Promise(resolve => resolve(successfulResponse)), - }; - - const result = await getIndices(es, mockIndexPatternCreationType, 'kibana', 1); - expect(result.length).toBe(2); - expect(result[0].name).toBe('1'); - expect(result[1].name).toBe('2'); - }); - - it('should ignore ccs query-all', async () => { - expect((await getIndices(null, mockIndexPatternCreationType, '*:')).length).toBe(0); - }); - - it('should ignore a single comma', async () => { - expect((await getIndices(null, mockIndexPatternCreationType, ',')).length).toBe(0); - expect((await getIndices(null, mockIndexPatternCreationType, ',*')).length).toBe(0); - expect((await getIndices(null, mockIndexPatternCreationType, ',foobar')).length).toBe(0); - }); - - it('should trim the input', async () => { - let index; - const es = { - search: jest.fn().mockImplementation(params => { - index = params.index; - }), - }; - - await getIndices(es, mockIndexPatternCreationType, 'kibana ', 1); - expect(index).toBe('kibana'); - }); - - it('should use the limit', async () => { - let limit; - const es = { - search: jest.fn().mockImplementation(params => { - limit = params.body.aggs.indices.terms.size; - }), - }; - - await getIndices(es, mockIndexPatternCreationType, 'kibana', 10); - expect(limit).toBe(10); - }); - - describe('errors', () => { - it('should handle errors gracefully', async () => { - const es = { - search: () => new Promise(resolve => resolve(errorResponse)), - }; - - const result = await getIndices(es, mockIndexPatternCreationType, 'kibana', 1); - expect(result.length).toBe(0); - }); - - it('should throw exceptions', async () => { - const es = { - search: () => { - throw new Error('Fail'); - }, - }; - - await expect(getIndices(es, mockIndexPatternCreationType, 'kibana', 1)).rejects.toThrow(); - }); - - it('should handle index_not_found_exception errors gracefully', async () => { - const es = { - search: () => new Promise((resolve, reject) => reject(exceptionResponse)), - }; - - const result = await getIndices(es, mockIndexPatternCreationType, 'kibana', 1); - expect(result.length).toBe(0); - }); - - it('should throw an exception if no limit is provided', async () => { - await expect(getIndices({}, mockIndexPatternCreationType, 'kibana')).rejects.toThrow(); - }); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/can_append_wildcard.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.test.ts similarity index 89% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/can_append_wildcard.test.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.test.ts index 055632bdd19e0..14139c2e08dc0 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/can_append_wildcard.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.test.ts @@ -17,13 +17,9 @@ * under the License. */ -import { canAppendWildcard } from '../can_append_wildcard'; +import { canAppendWildcard } from './can_append_wildcard'; describe('canAppendWildcard', () => { - test('ignores no data', () => { - expect(canAppendWildcard({})).toBeFalsy(); - }); - test('ignores symbols', () => { expect(canAppendWildcard('%')).toBeFalsy(); }); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.ts similarity index 94% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.ts index b47e645730aef..e9c4f75e4313b 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/can_append_wildcard.ts @@ -17,7 +17,7 @@ * under the License. */ -export const canAppendWildcard = keyPressed => { +export const canAppendWildcard = (keyPressed: string) => { // If it's not a letter, number or is something longer, reject it if (!keyPressed || !/[a-z0-9]/i.test(keyPressed) || keyPressed.length !== 1) { return false; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_illegal_characters.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_illegal_characters.ts similarity index 90% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_illegal_characters.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_illegal_characters.ts index 31485bb3daaa2..ca4fc8122903c 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_illegal_characters.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_illegal_characters.ts @@ -17,6 +17,6 @@ * under the License. */ -export function containsIllegalCharacters(pattern, illegalCharacters) { +export function containsIllegalCharacters(pattern: string, illegalCharacters: string[]) { return illegalCharacters.some(char => pattern.includes(char)); } diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/contains_invalid_characters.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_invalid_characters.test.ts similarity index 93% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/contains_invalid_characters.test.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_invalid_characters.test.ts index 05c4aba2571bd..640908d3db6d1 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/contains_invalid_characters.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/contains_invalid_characters.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { containsIllegalCharacters } from '../contains_illegal_characters'; +import { containsIllegalCharacters } from './contains_illegal_characters'; describe('containsIllegalCharacters', () => { it('returns true with illegal characters', () => { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/ensure_minimum_time.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.test.ts similarity index 96% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/ensure_minimum_time.test.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.test.ts index 99724cbf3a2a7..e5fcfe056923a 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/ensure_minimum_time.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ensureMinimumTime } from '../ensure_minimum_time'; +import { ensureMinimumTime } from './ensure_minimum_time'; describe('ensureMinimumTime', () => { it('resolves single promise', async done => { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.ts similarity index 97% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.ts index 0a6d3fcfbbdf0..84852ece485eb 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/ensure_minimum_time.ts @@ -27,7 +27,7 @@ export const DEFAULT_MINIMUM_TIME_MS = 300; export async function ensureMinimumTime( - promiseOrPromises, + promiseOrPromises: Promise | Array>, minimumTimeMs = DEFAULT_MINIMUM_TIME_MS ) { let returnValue; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/extract_time_fields.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.test.ts similarity index 89% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/extract_time_fields.test.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.test.ts index ec420e19817c7..4cd28090420a7 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/extract_time_fields.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.test.ts @@ -17,11 +17,14 @@ * under the License. */ -import { extractTimeFields } from '../extract_time_fields'; +import { extractTimeFields } from './extract_time_fields'; describe('extractTimeFields', () => { it('should handle no date fields', () => { - const fields = [{ type: 'text' }, { type: 'text' }]; + const fields = [ + { type: 'text', name: 'name' }, + { type: 'text', name: 'name' }, + ]; expect(extractTimeFields(fields)).toEqual([ { display: `The indices which match this index pattern don't contain any time fields.` }, diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.ts similarity index 92% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.ts index 1a9deefb217f2..0b95ec0a120da 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/extract_time_fields.ts @@ -18,8 +18,9 @@ */ import { i18n } from '@kbn/i18n'; +import { IFieldType } from '../../../../../../../../../plugins/data/public'; -export function extractTimeFields(fields) { +export function extractTimeFields(fields: IFieldType[]) { const dateFields = fields.filter(field => field.type === 'date'); const label = i18n.translate('kbn.management.createIndexPattern.stepTime.noTimeFieldsLabel', { defaultMessage: "The indices which match this index pattern don't contain any time fields.", diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts new file mode 100644 index 0000000000000..cd7c8278adcc7 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.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 { getIndices } from './get_indices'; +import { IndexPatternCreationConfig } from './../../../../../../../management/public'; +import { LegacyApiCaller } from '../../../../../../../../../plugins/data/public'; + +export const successfulResponse = { + hits: { + total: 1, + max_score: 0.0, + hits: [], + }, + aggregations: { + indices: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '1', + doc_count: 1, + }, + { + key: '2', + doc_count: 1, + }, + ], + }, + }, +}; + +export const exceptionResponse = { + body: { + error: { + root_cause: [ + { + type: 'index_not_found_exception', + reason: 'no such index', + index_uuid: '_na_', + 'resource.type': 'index_or_alias', + 'resource.id': 't', + index: 't', + }, + ], + type: 'transport_exception', + reason: 'unable to communicate with remote cluster [cluster_one]', + caused_by: { + type: 'index_not_found_exception', + reason: 'no such index', + index_uuid: '_na_', + 'resource.type': 'index_or_alias', + 'resource.id': 't', + index: 't', + }, + }, + }, + status: 500, +}; + +export const errorResponse = { + statusCode: 400, + error: 'Bad Request', +}; + +const mockIndexPatternCreationType = new IndexPatternCreationConfig({ + type: 'default', + name: 'name', + showSystemIndices: false, + httpClient: {}, + isBeta: false, +}); + +function esClientFactory(search: (params: any) => any): LegacyApiCaller { + return { + search, + msearch: () => ({ + abort: () => {}, + ...new Promise(resolve => resolve({})), + }), + }; +} + +const es = esClientFactory(() => successfulResponse); + +describe('getIndices', () => { + it('should work in a basic case', async () => { + const result = await getIndices(es, mockIndexPatternCreationType, 'kibana', 1); + expect(result.length).toBe(2); + expect(result[0].name).toBe('1'); + expect(result[1].name).toBe('2'); + }); + + it('should ignore ccs query-all', async () => { + expect((await getIndices(es, mockIndexPatternCreationType, '*:', 10)).length).toBe(0); + }); + + it('should ignore a single comma', async () => { + expect((await getIndices(es, mockIndexPatternCreationType, ',', 10)).length).toBe(0); + expect((await getIndices(es, mockIndexPatternCreationType, ',*', 10)).length).toBe(0); + expect((await getIndices(es, mockIndexPatternCreationType, ',foobar', 10)).length).toBe(0); + }); + + it('should trim the input', async () => { + let index; + const esClient = esClientFactory( + jest.fn().mockImplementation(params => { + index = params.index; + }) + ); + + await getIndices(esClient, mockIndexPatternCreationType, 'kibana ', 1); + expect(index).toBe('kibana'); + }); + + it('should use the limit', async () => { + let limit; + const esClient = esClientFactory( + jest.fn().mockImplementation(params => { + limit = params.body.aggs.indices.terms.size; + }) + ); + await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 10); + expect(limit).toBe(10); + }); + + describe('errors', () => { + it('should handle errors gracefully', async () => { + const esClient = esClientFactory(() => errorResponse); + const result = await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1); + expect(result.length).toBe(0); + }); + + it('should throw exceptions', async () => { + const esClient = esClientFactory(() => { + throw new Error('Fail'); + }); + + await expect( + getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1) + ).rejects.toThrow(); + }); + + it('should handle index_not_found_exception errors gracefully', async () => { + const esClient = esClientFactory( + () => new Promise((resolve, reject) => reject(exceptionResponse)) + ); + const result = await getIndices(esClient, mockIndexPatternCreationType, 'kibana', 1); + expect(result.length).toBe(0); + }); + }); +}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.ts similarity index 83% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.ts index 8159fff8220bd..3848c425e2d49 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.ts @@ -18,8 +18,16 @@ */ import { get, sortBy } from 'lodash'; +import { IndexPatternCreationConfig } from '../../../../../../../management/public'; +import { DataPublicPluginStart } from '../../../../../../../../../plugins/data/public'; +import { MatchedIndex } from '../types'; -export async function getIndices(es, indexPatternCreationType, rawPattern, limit) { +export async function getIndices( + es: DataPublicPluginStart['search']['__LEGACY']['esClient'], + indexPatternCreationType: IndexPatternCreationConfig, + rawPattern: string, + limit: number +): Promise { const pattern = rawPattern.trim(); // Searching for `*:` fails for CCS environments. The search request @@ -70,10 +78,10 @@ export async function getIndices(es, indexPatternCreationType, rawPattern, limit return sortBy( response.aggregations.indices.buckets - .map(bucket => { + .map((bucket: { key: string; doc_count: number }) => { return bucket.key; }) - .map(indexName => { + .map((indexName: string) => { return { name: indexName, tags: indexPatternCreationType.getIndexTags(indexName), diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/get_matched_indices.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.test.ts similarity index 53% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/get_matched_indices.test.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.test.ts index 625c128181ffe..7aba50a7ca12b 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/__jest__/get_matched_indices.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.test.ts @@ -17,24 +17,32 @@ * under the License. */ -import { getMatchedIndices } from '../get_matched_indices'; +import { getMatchedIndices } from './get_matched_indices'; -jest.mock('../../constants', () => ({ +jest.mock('./../constants', () => ({ MAX_NUMBER_OF_MATCHING_INDICES: 6, })); +const tags: string[] = []; const indices = [ - { name: 'kibana' }, - { name: 'es' }, - { name: 'logstash' }, - { name: 'packetbeat' }, - { name: 'metricbeat' }, - { name: '.kibana' }, + { name: 'kibana', tags }, + { name: 'es', tags }, + { name: 'logstash', tags }, + { name: 'packetbeat', tags }, + { name: 'metricbeat', tags }, + { name: '.kibana', tags }, ]; -const partialIndices = [{ name: 'kibana' }, { name: 'es' }, { name: '.kibana' }]; +const partialIndices = [ + { name: 'kibana', tags }, + { name: 'es', tags }, + { name: '.kibana', tags }, +]; -const exactIndices = [{ name: 'kibana' }, { name: '.kibana' }]; +const exactIndices = [ + { name: 'kibana', tags }, + { name: '.kibana', tags }, +]; describe('getMatchedIndices', () => { it('should return all indices', () => { @@ -43,26 +51,32 @@ describe('getMatchedIndices', () => { exactMatchedIndices, partialMatchedIndices, visibleIndices, - } = getMatchedIndices(indices, partialIndices, exactIndices, '*', true); + } = getMatchedIndices(indices, partialIndices, exactIndices, true); expect(allIndices).toEqual([ - { name: 'kibana' }, - { name: 'es' }, - { name: 'logstash' }, - { name: 'packetbeat' }, - { name: 'metricbeat' }, - { name: '.kibana' }, + { name: 'kibana', tags }, + { name: 'es', tags }, + { name: 'logstash', tags }, + { name: 'packetbeat', tags }, + { name: 'metricbeat', tags }, + { name: '.kibana', tags }, ]); - expect(exactMatchedIndices).toEqual([{ name: 'kibana' }, { name: '.kibana' }]); + expect(exactMatchedIndices).toEqual([ + { name: 'kibana', tags }, + { name: '.kibana', tags }, + ]); expect(partialMatchedIndices).toEqual([ - { name: 'kibana' }, - { name: 'es' }, - { name: '.kibana' }, + { name: 'kibana', tags }, + { name: 'es', tags }, + { name: '.kibana', tags }, ]); - expect(visibleIndices).toEqual([{ name: 'kibana' }, { name: '.kibana' }]); + expect(visibleIndices).toEqual([ + { name: 'kibana', tags }, + { name: '.kibana', tags }, + ]); }); it('should return all indices except for system indices', () => { @@ -71,31 +85,38 @@ describe('getMatchedIndices', () => { exactMatchedIndices, partialMatchedIndices, visibleIndices, - } = getMatchedIndices(indices, partialIndices, exactIndices, '*', false); + } = getMatchedIndices(indices, partialIndices, exactIndices, false); expect(allIndices).toEqual([ - { name: 'kibana' }, - { name: 'es' }, - { name: 'logstash' }, - { name: 'packetbeat' }, - { name: 'metricbeat' }, + { name: 'kibana', tags }, + { name: 'es', tags }, + { name: 'logstash', tags }, + { name: 'packetbeat', tags }, + { name: 'metricbeat', tags }, ]); - expect(exactMatchedIndices).toEqual([{ name: 'kibana' }]); + expect(exactMatchedIndices).toEqual([{ name: 'kibana', tags }]); - expect(partialMatchedIndices).toEqual([{ name: 'kibana' }, { name: 'es' }]); + expect(partialMatchedIndices).toEqual([ + { name: 'kibana', tags }, + { name: 'es', tags }, + ]); - expect(visibleIndices).toEqual([{ name: 'kibana' }]); + expect(visibleIndices).toEqual([{ name: 'kibana', tags }]); }); it('should return partial matches as visible if there are no exact', () => { - const { visibleIndices } = getMatchedIndices(indices, partialIndices, [], '*', true); + const { visibleIndices } = getMatchedIndices(indices, partialIndices, [], true); - expect(visibleIndices).toEqual([{ name: 'kibana' }, { name: 'es' }, { name: '.kibana' }]); + expect(visibleIndices).toEqual([ + { name: 'kibana', tags }, + { name: 'es', tags }, + { name: '.kibana', tags }, + ]); }); it('should return all indices as visible if there are no exact or partial', () => { - const { visibleIndices } = getMatchedIndices(indices, [], [], '*', true); + const { visibleIndices } = getMatchedIndices(indices, [], [], true); expect(visibleIndices).toEqual(indices); }); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.ts similarity index 86% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.ts index 19a829a83a2b2..cc3fd4075aa0e 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_matched_indices.ts @@ -19,19 +19,21 @@ import { MAX_NUMBER_OF_MATCHING_INDICES } from '../constants'; -function isSystemIndex(index) { +function isSystemIndex(index: string): boolean { if (index.startsWith('.')) { return true; } if (index.includes(':')) { - return index.split(':').reduce((isSystem, index) => isSystem || isSystemIndex(index), false); + return index + .split(':') + .reduce((isSystem: boolean, idx) => isSystem || isSystemIndex(idx), false); } return false; } -function filterSystemIndices(indices, isIncludingSystemIndices) { +function filterSystemIndices(indices: MatchedIndex[], isIncludingSystemIndices: boolean) { if (!indices) { return indices; } @@ -62,12 +64,14 @@ function filterSystemIndices(indices, isIncludingSystemIndices) { This is the result of searching against a query that already ends in `*`. We call this `exact` matches because ES is telling us exactly what it matches */ + +import { MatchedIndex } from '../types'; + export function getMatchedIndices( - unfilteredAllIndices, - unfilteredPartialMatchedIndices, - unfilteredExactMatchedIndices, - query, - isIncludingSystemIndices + unfilteredAllIndices: MatchedIndex[], + unfilteredPartialMatchedIndices: MatchedIndex[], + unfilteredExactMatchedIndices: MatchedIndex[], + isIncludingSystemIndices: boolean = false ) { const allIndices = filterSystemIndices(unfilteredAllIndices, isIncludingSystemIndices); const partialMatchedIndices = filterSystemIndices( diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/index.js rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/index.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/types.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/types.ts new file mode 100644 index 0000000000000..93bb6920c6981 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/types.ts @@ -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. + */ + +export interface MatchedIndex { + name: string; + tags: string[]; +} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/__snapshots__/advanced_settings.test.tsx.snap b/src/legacy/core_plugins/kibana/public/management/sections/settings/__snapshots__/advanced_settings.test.tsx.snap index 4814432c832e2..e76435fdb73b2 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/__snapshots__/advanced_settings.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/__snapshots__/advanced_settings.test.tsx.snap @@ -6,7 +6,7 @@ exports[`AdvancedSettings should render read-only when saving is disabled 1`] = gutterSize="none" > - + - + @@ -139,7 +139,7 @@ exports[`AdvancedSettings should render read-only when saving is disabled 1`] = } showNoResultsMessage={true} /> - - + - + @@ -322,7 +322,7 @@ exports[`AdvancedSettings should render specific setting if given setting key 1` } showNoResultsMessage={true} /> - ({ npStart: mockConfig(), @@ -215,6 +217,22 @@ function mockConfig() { core: { uiSettings: config, }, + plugins: { + advancedSettings: { + component: { + register: jest.fn(), + get: () => { + const foo: React.ComponentType = () =>
Hello
; + foo.displayName = 'foo_component'; + return foo; + }, + componentType: { + PAGE_TITLE_COMPONENT: 'page_title_component', + PAGE_SUBTITLE_COMPONENT: 'page_subtitle_component', + }, + }, + }, + }, }; } diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/advanced_settings.tsx b/src/legacy/core_plugins/kibana/public/management/sections/settings/advanced_settings.tsx index 569ef73f2b453..c995b391d3d2d 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/advanced_settings.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/advanced_settings.tsx @@ -31,14 +31,6 @@ import { getAriaName, toEditableConfig, DEFAULT_CATEGORY } from './lib'; import { FieldSetting, IQuery } from './types'; -import { - registerDefaultComponents, - PAGE_TITLE_COMPONENT, - PAGE_SUBTITLE_COMPONENT, - PAGE_FOOTER_COMPONENT, -} from './components/default_component_registry'; -import { getSettingsComponent } from './components/component_registry'; - interface AdvancedSettingsProps { queryText: string; enableSaving: boolean; @@ -75,8 +67,6 @@ export class AdvancedSettings extends Component diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/__snapshots__/component_registry.test.tsx.snap b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/__snapshots__/component_registry.test.tsx.snap deleted file mode 100644 index 070b387057061..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/__snapshots__/component_registry.test.tsx.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`getSettingsComponent should throw an error when requesting a component that does not exist 1`] = `"Component not found with id does not exist"`; - -exports[`registerSettingsComponent should disallow registering a component with a duplicate id 1`] = `"Component with id test2 is already registered."`; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.test.tsx b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.test.tsx deleted file mode 100644 index 24e9e5dd3809c..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.test.tsx +++ /dev/null @@ -1,82 +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 React, { FunctionComponent } from 'react'; -import { - tryRegisterSettingsComponent, - registerSettingsComponent, - getSettingsComponent, -} from './component_registry'; - -describe('tryRegisterSettingsComponent', () => { - it('should allow a component to be registered', () => { - const component = () =>
; - expect(tryRegisterSettingsComponent('tryTest1', component)).toEqual(true); - }); - - it('should return false if the component is already registered, and not allow an override', () => { - const component = () =>
; - expect(tryRegisterSettingsComponent('tryTest2', component)).toEqual(true); - - const updatedComponent = () =>
; - expect(tryRegisterSettingsComponent('tryTest2', updatedComponent)).toEqual(false); - expect(getSettingsComponent('tryTest2')).toBe(component); - }); -}); - -describe('registerSettingsComponent', () => { - it('should allow a component to be registered', () => { - const component = () =>
; - registerSettingsComponent('test', component); - }); - - it('should disallow registering a component with a duplicate id', () => { - const component = () =>
; - registerSettingsComponent('test2', component); - expect(() => registerSettingsComponent('test2', () => )).toThrowErrorMatchingSnapshot(); - }); - - it('should allow a component to be overriden', () => { - const component = () =>
; - registerSettingsComponent('test3', component); - - const anotherComponent = () => ; - registerSettingsComponent('test3', anotherComponent, true); - - expect(getSettingsComponent('test3')).toBe(anotherComponent); - }); - - it('should set a displayName for the component', () => { - const component = () =>
; - registerSettingsComponent('display_name_component', component); - expect((component as FunctionComponent).displayName).toEqual('display_name_component'); - }); -}); - -describe('getSettingsComponent', () => { - it('should allow a component to be retrieved', () => { - const component = () =>
; - registerSettingsComponent('test4', component); - expect(getSettingsComponent('test4')).toBe(component); - }); - - it('should throw an error when requesting a component that does not exist', () => { - expect(() => getSettingsComponent('does not exist')).toThrowErrorMatchingSnapshot(); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.ts b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.ts deleted file mode 100644 index b58180c498edf..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.ts +++ /dev/null @@ -1,83 +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 { ComponentType } from 'react'; - -type Id = string; -const registry: Record | undefined>> = {}; - -/** - * Attempts to register the provided component. - * If a component with that ID is already registered, then the registration fails. - * - * @param {*} id the id of the component to register - * @param {*} component the component - */ -export function tryRegisterSettingsComponent( - id: Id, - component: ComponentType | undefined> -) { - if (id in registry) { - return false; - } - - registerSettingsComponent(id, component); - return true; -} - -/** - * Attempts to register the provided component, with the ability to optionally allow - * the component to override an existing one. - * - * If the intent is to override, then `allowOverride` must be set to true, otherwise an exception is thrown. - * - * @param {*} id the id of the component to register - * @param {*} component the component - * @param {*} allowOverride (default: false) - optional flag to allow this component to override a previously registered component - */ -export function registerSettingsComponent( - id: Id, - component: ComponentType | undefined>, - allowOverride = false -) { - if (!allowOverride && id in registry) { - throw new Error(`Component with id ${id} is already registered.`); - } - - // Setting a display name if one does not already exist. - // This enhances the snapshots, as well as the debugging experience. - if (!component.displayName) { - component.displayName = id; - } - - registry[id] = component; -} - -/** - * Retrieve a registered component by its ID. - * If the component does not exist, then an exception is thrown. - * - * @param {*} id the ID of the component to retrieve - */ -export function getSettingsComponent(id: Id): ComponentType | undefined> { - if (!(id in registry)) { - throw new Error(`Component not found with id ${id}`); - } - return registry[id]; -} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.tsx b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.tsx deleted file mode 100644 index ff3f75b79baef..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.tsx +++ /dev/null @@ -1,44 +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 React from 'react'; -import { registerDefaultComponents, PAGE_TITLE_COMPONENT } from './default_component_registry'; -import { getSettingsComponent, registerSettingsComponent } from './component_registry'; -import { PageTitle } from './page_title'; - -describe('default_component_registry', () => { - it('should register default components with the registry', () => { - registerDefaultComponents(); - expect(getSettingsComponent(PAGE_TITLE_COMPONENT)).toEqual(PageTitle); - }); - - it('should be able to call "registerDefaultComponents" several times without throwing', () => { - registerDefaultComponents(); - registerDefaultComponents(); - registerDefaultComponents(); - }); - - it('should not override components if they are already registered', () => { - const newComponent = () =>
; - registerSettingsComponent(PAGE_TITLE_COMPONENT, newComponent, true); - registerDefaultComponents(); - - expect(getSettingsComponent(PAGE_TITLE_COMPONENT)).toEqual(newComponent); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.ts b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.ts deleted file mode 100644 index 80b2f2e79b9c7..0000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.ts +++ /dev/null @@ -1,33 +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 { tryRegisterSettingsComponent } from './component_registry'; -import { PageTitle } from './page_title'; -import { PageSubtitle } from './page_subtitle'; -import { PageFooter } from './page_footer'; - -export const PAGE_TITLE_COMPONENT = 'advanced_settings_page_title'; -export const PAGE_SUBTITLE_COMPONENT = 'advanced_settings_page_subtitle'; -export const PAGE_FOOTER_COMPONENT = 'advanced_settings_page_footer'; - -export function registerDefaultComponents() { - tryRegisterSettingsComponent(PAGE_TITLE_COMPONENT, PageTitle); - tryRegisterSettingsComponent(PAGE_SUBTITLE_COMPONENT, PageSubtitle); - tryRegisterSettingsComponent(PAGE_FOOTER_COMPONENT, PageFooter); -} diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.ts b/src/legacy/core_plugins/kibana/public/visualize/index.ts index e7170836cf749..83b820a8e3134 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/index.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/index.ts @@ -21,7 +21,6 @@ import { PluginInitializerContext } from 'kibana/public'; import { VisualizePlugin } from './plugin'; export * from './np_ready/visualize_constants'; -export { showNewVisModal } from './np_ready/wizard'; export { VisualizeConstants, createVisualizeEditUrl } from './np_ready/visualize_constants'; // Core will be looking for this when loading our plugin in the new platform diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts index 15e9c73a39eff..428e6cb225710 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts @@ -23,6 +23,7 @@ import { SavedObjectsClientContract, ToastsStart, IUiSettingsClient, + I18nStart, } from 'kibana/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; @@ -57,6 +58,7 @@ export interface VisualizeKibanaServices { visualizeCapabilities: any; visualizations: VisualizationsStart; usageCollection?: UsageCollectionSetup; + I18nContext: I18nStart['Context']; } let services: VisualizeKibanaServices | null = null; diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts index b185dc577a3aa..bb24870c5a5f3 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts @@ -44,9 +44,6 @@ export { IPrivate } from 'ui/private'; // @ts-ignore export { PrivateProvider } from 'ui/private/private'; -export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal'; -export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal'; - export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; // @ts-ignore diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/_index.scss b/src/legacy/core_plugins/kibana/public/visualize/np_ready/_index.scss index f97ae012055b0..847e72bf29fbc 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/_index.scss +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/_index.scss @@ -7,4 +7,3 @@ @import 'editor/index'; @import 'listing/index'; -@import 'wizard/index'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js index 96a583bec7dc9..46ae45c3a5fa2 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js @@ -31,6 +31,10 @@ import { getEditBreadcrumbs } from '../breadcrumbs'; import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util'; import { FilterStateManager } from '../../../../../data/public'; import { unhashUrl } from '../../../../../../../plugins/kibana_utils/public'; +import { + SavedObjectSaveModal, + showSaveModal, +} from '../../../../../../../plugins/saved_objects/public'; import { initVisEditorDirective } from './visualization_editor'; import { initVisualizationDirective } from './visualization'; @@ -40,8 +44,6 @@ import { absoluteToParsedUrl, KibanaParsedUrl, migrateLegacyQuery, - SavedObjectSaveModal, - showSaveModal, stateMonitorFactory, DashboardConstants, } from '../../legacy_imports'; @@ -94,10 +96,10 @@ function VisualizeAppController( core: { docLinks }, savedQueryService, uiSettings, + I18nContext, } = getServices(); const filterStateManager = new FilterStateManager(globalState, getAppState, filterManager); - const queryFilter = filterManager; // Retrieve the resolved SavedVis instance. const savedVis = $route.current.locals.savedVis; const _applyVis = () => { @@ -192,7 +194,7 @@ function VisualizeAppController( description={savedVis.description} /> ); - showSaveModal(saveModal); + showSaveModal(saveModal, I18nContext); }, }, ] @@ -311,11 +313,11 @@ function VisualizeAppController( return appState; })(); - $scope.filters = queryFilter.getFilters(); + $scope.filters = filterManager.getFilters(); $scope.onFiltersUpdated = filters => { - // The filters will automatically be set when the queryFilter emits an update event (see below) - queryFilter.setFilters(filters); + // The filters will automatically be set when the filterManager emits an update event (see below) + filterManager.setFilters(filters); }; $scope.showSaveQuery = visualizeCapabilities.saveQuery; @@ -426,15 +428,15 @@ function VisualizeAppController( // update the searchSource when filters update subscriptions.add( - subscribeWithScope($scope, queryFilter.getUpdates$(), { + subscribeWithScope($scope, filterManager.getUpdates$(), { next: () => { - $scope.filters = queryFilter.getFilters(); - $scope.globalFilters = queryFilter.getGlobalFilters(); + $scope.filters = filterManager.getFilters(); + $scope.globalFilters = filterManager.getGlobalFilters(); }, }) ); subscriptions.add( - subscribeWithScope($scope, queryFilter.getFetches$(), { + subscribeWithScope($scope, filterManager.getFetches$(), { next: $scope.fetch, }) ); @@ -500,7 +502,7 @@ function VisualizeAppController( language: localStorage.get('kibana.userQueryLanguage') || uiSettings.get('search:queryLanguage'), }; - queryFilter.setFilters(queryFilter.getGlobalFilters()); + filterManager.setFilters(filterManager.getGlobalFilters()); $state.save(); $scope.fetch(); }; @@ -510,8 +512,8 @@ function VisualizeAppController( $state.save(); const savedQueryFilters = savedQuery.attributes.filters || []; - const globalFilters = queryFilter.getGlobalFilters(); - queryFilter.setFilters([...globalFilters, ...savedQueryFilters]); + const globalFilters = filterManager.getGlobalFilters(); + filterManager.setFilters([...globalFilters, ...savedQueryFilters]); if (savedQuery.attributes.timefilter) { timefilter.setTime({ diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.html b/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.html index 522d20fffafd3..17caaba144a44 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.html +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.html @@ -9,15 +9,4 @@ edit-item="listingController.editItem" listing-limit="listingController.listingLimit" > - - -
diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js index ac8308e1cd1c5..6bac4e4c62efa 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/listing/visualize_listing.js @@ -19,7 +19,7 @@ import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util'; import { VisualizeListingTable } from './visualize_listing_table'; -import { NewVisModal } from '../wizard/new_vis_modal'; + import { VisualizeConstants } from '../visualize_constants'; import { i18n } from '@kbn/i18n'; @@ -30,17 +30,6 @@ export function initListingDirective(app) { app.directive('visualizeListingTable', reactDirective => reactDirective(wrapInI18nContext(VisualizeListingTable)) ); - app.directive('newVisModal', reactDirective => - reactDirective(wrapInI18nContext(NewVisModal), [ - ['visTypesRegistry', { watchDepth: 'collection' }], - ['onClose', { watchDepth: 'reference' }], - ['addBasePath', { watchDepth: 'reference' }], - ['uiSettings', { watchDepth: 'reference' }], - ['savedObjects', { watchDepth: 'reference' }], - ['usageCollection', { watchDepth: 'reference' }], - 'isOpen', - ]) - ); } export function VisualizeListingController($injector, createNewVis) { @@ -59,21 +48,18 @@ export function VisualizeListingController($injector, createNewVis) { uiSettings, visualizations, core: { docLinks, savedObjects }, - usageCollection, } = getServices(); const kbnUrl = $injector.get('kbnUrl'); timefilter.disableAutoRefreshSelector(); timefilter.disableTimeRangeSelector(); - this.showNewVisModal = false; this.addBasePath = addBasePath; this.uiSettings = uiSettings; this.savedObjects = savedObjects; - this.usageCollection = usageCollection; this.createNewVis = () => { - this.showNewVisModal = true; + visualizations.showNewVisModal(); }; this.editItem = ({ editUrl }) => { @@ -85,19 +71,15 @@ export function VisualizeListingController($injector, createNewVis) { return addBasePath(editUrl); }; - this.closeNewVisModal = () => { - this.showNewVisModal = false; - // In case the user came via a URL to this page, change the URL to the regular landing page URL after closing the modal - if (createNewVis) { - kbnUrl.changePath(VisualizeConstants.LANDING_PAGE_PATH); - } - }; - if (createNewVis) { // In case the user navigated to the page via the /visualize/new URL we start the dialog immediately - this.createNewVis(); + visualizations.showNewVisModal({ + onClose: () => { + // In case the user came via a URL to this page, change the URL to the regular landing page URL after closing the modal + kbnUrl.changePath(VisualizeConstants.LANDING_PAGE_PATH); + }, + }); } - this.visTypeRegistry = visualizations.types; this.fetchItems = filter => { const isLabsEnabled = uiSettings.get('visualize:enableLabs'); diff --git a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts index 8e7487fee55f6..ce93fe7c2d578 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts @@ -56,7 +56,7 @@ export interface VisualizePluginSetupDependencies { legacyChrome: Chrome; }; home: HomePublicPluginSetup; - kibana_legacy: KibanaLegacySetup; + kibanaLegacy: KibanaLegacySetup; usageCollection?: UsageCollectionSetup; } @@ -72,9 +72,9 @@ export class VisualizePlugin implements Plugin { public async setup( core: CoreSetup, - { home, kibana_legacy, __LEGACY, usageCollection }: VisualizePluginSetupDependencies + { home, kibanaLegacy, __LEGACY, usageCollection }: VisualizePluginSetupDependencies ) { - kibana_legacy.registerLegacyApp({ + kibanaLegacy.registerLegacyApp({ id: 'visualize', title: 'Visualize', mount: async ({ core: contextCore }, params) => { @@ -108,10 +108,11 @@ export class VisualizePlugin implements Plugin { share, toastNotifications: contextCore.notifications.toasts, uiSettings: contextCore.uiSettings, - config: kibana_legacy.config, + config: kibanaLegacy.config, visualizeCapabilities: contextCore.application.capabilities.visualize, visualizations, usageCollection, + I18nContext: contextCore.i18n.Context, }; setServices(deps); diff --git a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts index 0598c88c80ba7..b68b2e40aad9e 100644 --- a/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts +++ b/src/legacy/core_plugins/management/public/np_ready/services/index_pattern_management/creation/config.ts @@ -102,7 +102,7 @@ export class IndexPatternCreationConfig { return this.showSystemIndices; } - public getIndexTags() { + public getIndexTags(indexName: string) { return []; } diff --git a/src/legacy/core_plugins/telemetry/public/views/management/management.js b/src/legacy/core_plugins/telemetry/public/views/management/management.js index 796caf1c8cfe6..7032775e391bb 100644 --- a/src/legacy/core_plugins/telemetry/public/views/management/management.js +++ b/src/legacy/core_plugins/telemetry/public/views/management/management.js @@ -19,7 +19,7 @@ import React from 'react'; import routes from 'ui/routes'; -import { registerSettingsComponent, PAGE_FOOTER_COMPONENT } from 'ui/management'; +import { npSetup } from 'ui/new_platform'; import { TelemetryOptInProvider } from '../../services'; import { TelemetryForm } from '../../components'; @@ -27,6 +27,7 @@ routes.defaults(/\/management/, { resolve: { telemetryManagementSection: function(Private) { const telemetryOptInProvider = Private(TelemetryOptInProvider); + const componentRegistry = npSetup.plugins.advancedSettings.component; const Component = props => ( ); - registerSettingsComponent(PAGE_FOOTER_COMPONENT, Component, true); + componentRegistry.register( + componentRegistry.componentType.PAGE_FOOTER_COMPONENT, + Component, + true + ); }, }, }); diff --git a/src/legacy/core_plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts b/src/legacy/core_plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts index cf6059faf0c05..78685cd6becc8 100644 --- a/src/legacy/core_plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts +++ b/src/legacy/core_plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts @@ -136,7 +136,7 @@ describe('telemetry_usage_collector', () => { const collectorOptions = createTelemetryUsageCollector(usageCollector, server); expect(collectorOptions.type).toBe('static_telemetry'); - expect(await collectorOptions.fetch()).toEqual(expectedObject); + expect(await collectorOptions.fetch({} as any)).toEqual(expectedObject); // Sending any as the callCluster client because it's not needed in this collector but TS requires it when calling it. }); }); }); diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_kibana.js b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_kibana.ts similarity index 62% rename from src/legacy/core_plugins/telemetry/server/telemetry_collection/get_kibana.js rename to src/legacy/core_plugins/telemetry/server/telemetry_collection/get_kibana.ts index e65606a83afc8..537d5a85911cd 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_kibana.js +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_kibana.ts @@ -17,9 +17,27 @@ * under the License. */ -import { get, omit } from 'lodash'; +import { omit } from 'lodash'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; -export function handleKibanaStats(server, response) { +export interface KibanaUsageStats { + kibana: { + index: string; + }; + kibana_stats: { + os: { + platform: string; + platformRelease: string; + distro?: string; + distroRelease?: string; + }; + }; + + [plugin: string]: any; +} + +export function handleKibanaStats(server: any, response?: KibanaUsageStats) { if (!response) { server.log( ['warning', 'telemetry', 'local-stats'], @@ -30,8 +48,17 @@ export function handleKibanaStats(server, response) { const { kibana, kibana_stats: kibanaStats, ...plugins } = response; - const platform = get(kibanaStats, 'os.platform', 'unknown'); - const platformRelease = get(kibanaStats, 'os.platformRelease', 'unknown'); + const os = { + platform: 'unknown', + platformRelease: 'unknown', + ...kibanaStats.os, + }; + const formattedOsStats = Object.entries(os).reduce((acc, [key, value]) => { + return { + ...acc, + [`${key}s`]: [{ [key]: value, count: 1 }], + }; + }, {}); const version = server .config() @@ -44,16 +71,16 @@ export function handleKibanaStats(server, response) { ...omit(kibana, 'index'), // discard index count: 1, indices: 1, - os: { - platforms: [{ platform, count: 1 }], - platformReleases: [{ platformRelease, count: 1 }], - }, + os: formattedOsStats, versions: [{ version, count: 1 }], plugins, }; } -export async function getKibana(usageCollection, callWithInternalUser) { +export async function getKibana( + usageCollection: UsageCollectionSetup, + callWithInternalUser: CallCluster +): Promise { const usage = await usageCollection.bulkFetch(callWithInternalUser); return usageCollection.toObject(usage); } diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.ts b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.ts index a4ea2eb534226..8adb6d237bee8 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.ts @@ -22,18 +22,25 @@ import { get, omit } from 'lodash'; import { getClusterInfo } from './get_cluster_info'; import { getClusterStats } from './get_cluster_stats'; // @ts-ignore -import { getKibana, handleKibanaStats } from './get_kibana'; +import { getKibana, handleKibanaStats, KibanaUsageStats } from './get_kibana'; import { StatsGetter } from '../collection_manager'; /** * Handle the separate local calls by combining them into a single object response that looks like the * "cluster_stats" document from X-Pack monitoring. * + * @param {Object} server ?? * @param {Object} clusterInfo Cluster info (GET /) * @param {Object} clusterStats Cluster stats (GET /_cluster/stats) + * @param {Object} kibana The Kibana Usage stats * @return {Object} A combined object containing the different responses. */ -export function handleLocalStats(server: any, clusterInfo: any, clusterStats: any, kibana: any) { +export function handleLocalStats( + server: any, + clusterInfo: any, + clusterStats: any, + kibana: KibanaUsageStats +) { return { timestamp: new Date().toISOString(), cluster_uuid: get(clusterInfo, 'cluster_uuid'), diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx index 81c866923232e..f5ce55e82967d 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx @@ -24,7 +24,7 @@ import { act } from 'react-dom/test-utils'; import { IndexPattern } from 'src/plugins/data/public'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggType, AggGroupNames } from '../legacy_imports'; +import { IAggType, AggGroupNames } from '../legacy_imports'; import { DefaultEditorAgg, DefaultEditorAggProps } from './agg'; import { DefaultEditorAggParams } from './agg_params'; import { AGGS_ACTION_KEYS } from './agg_group_state'; @@ -117,7 +117,7 @@ describe('DefaultEditorAgg component', () => { (defaultProps.agg as any).brandNew = false; defaultProps.agg.type = { makeLabel: () => 'Agg description', - } as AggType; + } as IAggType; const comp = mount(); act(() => { @@ -258,11 +258,11 @@ describe('DefaultEditorAgg component', () => { it('should disable min_doc_count when agg is histogram or date_histogram', () => { defaultProps.agg.type = { name: 'histogram', - } as AggType; + } as IAggType; const compHistogram = shallow(); defaultProps.agg.type = { name: 'date_histogram', - } as AggType; + } as IAggType; const compDateHistogram = shallow(); expect(compHistogram.find(DefaultEditorAggParams).props()).toHaveProperty('disabledParams', [ @@ -276,7 +276,7 @@ describe('DefaultEditorAgg component', () => { it('should set error when agg is not histogram or date_histogram', () => { defaultProps.agg.type = { name: 'aggType', - } as AggType; + } as IAggType; const comp = shallow(); expect(comp.find(DefaultEditorAggParams).prop('aggError')).toBeDefined(); @@ -285,7 +285,7 @@ describe('DefaultEditorAgg component', () => { it('should set min_doc_count to true when agg type was changed to histogram', () => { defaultProps.agg.type = { name: 'aggType', - } as AggType; + } as IAggType; const comp = mount(); comp.setProps({ agg: { ...defaultProps.agg, type: { name: 'histogram' } } }); @@ -299,7 +299,7 @@ describe('DefaultEditorAgg component', () => { it('should set min_doc_count to 0 when agg type was changed to date_histogram', () => { defaultProps.agg.type = { name: 'aggType', - } as AggType; + } as IAggType; const comp = mount(); comp.setProps({ agg: { ...defaultProps.agg, type: { name: 'date_histogram' } } }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg.tsx index 871bd0cdf6811..5450c29450bac 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg.tsx @@ -28,7 +28,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { AggConfig } from '../legacy_imports'; +import { IAggConfig } from '../legacy_imports'; import { DefaultEditorAggParams } from './agg_params'; import { DefaultEditorAggCommonProps } from './agg_common_props'; import { AGGS_ACTION_KEYS, AggsAction } from './agg_group_state'; @@ -36,7 +36,7 @@ import { RowsOrColumnsControl } from './controls/rows_or_columns'; import { RadiusRatioOptionControl } from './controls/radius_ratio_option'; export interface DefaultEditorAggProps extends DefaultEditorAggCommonProps { - agg: AggConfig; + agg: IAggConfig; aggIndex: number; aggIsTooLow: boolean; dragHandleProps: {} | null; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_add.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_add.tsx index f5175126c31c1..d8df5b315fca0 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_add.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_add.tsx @@ -29,10 +29,10 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { AggConfig, AggGroupNames, Schema } from '../legacy_imports'; +import { IAggConfig, AggGroupNames, Schema } from '../legacy_imports'; interface DefaultEditorAggAddProps { - group?: AggConfig[]; + group?: IAggConfig[]; groupName: string; schemas: Schema[]; stats: { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts index 8d803810b647a..17d2c18d2532c 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts @@ -18,25 +18,25 @@ */ import { VisState, VisParams } from 'src/legacy/core_plugins/visualizations/public'; -import { AggType, AggConfig, AggGroupNames, Schema } from '../legacy_imports'; +import { IAggType, IAggConfig, AggGroupNames, Schema } from '../legacy_imports'; -type AggId = AggConfig['id']; -type AggParams = AggConfig['params']; +type AggId = IAggConfig['id']; +type AggParams = IAggConfig['params']; export type AddSchema = (schemas: Schema) => void; -export type ReorderAggs = (sourceAgg: AggConfig, destinationAgg: AggConfig) => void; +export type ReorderAggs = (sourceAgg: IAggConfig, destinationAgg: IAggConfig) => void; export interface DefaultEditorCommonProps { formIsTouched: boolean; groupName: AggGroupNames; - metricAggs: AggConfig[]; + metricAggs: IAggConfig[]; state: VisState; setAggParamValue: ( aggId: AggId, paramName: T, value: AggParams[T] ) => void; - onAggTypeChange: (aggId: AggId, aggType: AggType) => void; + onAggTypeChange: (aggId: AggId, aggType: IAggType) => void; } export interface DefaultEditorAggCommonProps extends DefaultEditorCommonProps { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx index 9cbcc31bdc60e..c36c0176439f9 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx @@ -21,7 +21,7 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfigs, AggConfig, Schema } from '../legacy_imports'; +import { IAggConfigs, IAggConfig, Schema } from '../legacy_imports'; import { DefaultEditorAggGroup, DefaultEditorAggGroupProps } from './agg_group'; import { DefaultEditorAgg } from './agg'; import { DefaultEditorAggAdd } from './agg_add'; @@ -56,7 +56,7 @@ jest.mock('./agg_add', () => ({ describe('DefaultEditorAgg component', () => { let defaultProps: DefaultEditorAggGroupProps; - let aggs: AggConfigs; + let aggs: IAggConfigs; let setTouched: jest.Mock; let setValidity: jest.Mock; let reorderAggs: jest.Mock; @@ -76,7 +76,7 @@ describe('DefaultEditorAgg component', () => { }, }, schema: { group: 'metrics' }, - } as AggConfig, + } as IAggConfig, { id: '3', params: { @@ -85,7 +85,7 @@ describe('DefaultEditorAgg component', () => { }, }, schema: { group: 'metrics' }, - } as AggConfig, + } as IAggConfig, { id: '2', params: { @@ -94,9 +94,9 @@ describe('DefaultEditorAgg component', () => { }, }, schema: { group: 'buckets' }, - } as AggConfig, + } as IAggConfig, ], - } as AggConfigs; + } as IAggConfigs; defaultProps = { formIsTouched: false, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx index 3491414bec809..768a9669025e4 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx @@ -30,7 +30,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { AggConfig, aggGroupNamesMap, AggGroupNames, Schema } from '../legacy_imports'; +import { IAggConfig, aggGroupNamesMap, AggGroupNames, Schema } from '../legacy_imports'; import { DefaultEditorAgg } from './agg'; import { DefaultEditorAggAdd } from './agg_add'; import { AddSchema, ReorderAggs, DefaultEditorAggCommonProps } from './agg_common_props'; @@ -69,8 +69,8 @@ function DefaultEditorAggGroup({ }: DefaultEditorAggGroupProps) { const groupNameLabel = (aggGroupNamesMap() as any)[groupName]; // e.g. buckets can have no aggs - const group: AggConfig[] = useMemo( - () => state.aggs.aggs.filter((agg: AggConfig) => agg.schema.group === groupName) || [], + const group: IAggConfig[] = useMemo( + () => state.aggs.aggs.filter((agg: IAggConfig) => agg.schema.group === groupName) || [], [groupName, state.aggs.aggs] ); @@ -151,7 +151,7 @@ function DefaultEditorAggGroup({ )} <> - {group.map((agg: AggConfig, index: number) => ( + {group.map((agg: IAggConfig, index: number) => ( { - let group: AggConfig[]; + let group: IAggConfig[]; beforeEach(() => { group = [ @@ -39,7 +39,7 @@ describe('DefaultEditorGroup helpers', () => { }, }, schema: { name: 'metric', min: 1, mustBeFirst: true }, - } as AggConfig, + } as IAggConfig, { id: '2', params: { @@ -48,7 +48,7 @@ describe('DefaultEditorGroup helpers', () => { }, }, schema: { name: 'metric', min: 2 }, - } as AggConfig, + } as IAggConfig, ]; }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_helper.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_helper.tsx index 87f0d00d50a1d..d2e8e5401c0f7 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_helper.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_helper.tsx @@ -18,12 +18,12 @@ */ import { findIndex, isEmpty } from 'lodash'; -import { AggConfig } from '../legacy_imports'; +import { IAggConfig } from '../legacy_imports'; import { AggsState } from './agg_group_state'; -const isAggRemovable = (agg: AggConfig, group: AggConfig[]) => { +const isAggRemovable = (agg: IAggConfig, group: IAggConfig[]) => { const metricCount = group.reduce( - (count, aggregation: AggConfig) => + (count, aggregation: IAggConfig) => aggregation.schema.name === agg.schema.name ? ++count : count, 0 ); @@ -31,20 +31,20 @@ const isAggRemovable = (agg: AggConfig, group: AggConfig[]) => { return metricCount > agg.schema.min; }; -const getEnabledMetricAggsCount = (group: AggConfig[]) => { +const getEnabledMetricAggsCount = (group: IAggConfig[]) => { return group.reduce( - (count, aggregation: AggConfig) => + (count, aggregation: IAggConfig) => aggregation.schema.name === 'metric' && aggregation.enabled ? ++count : count, 0 ); }; -const calcAggIsTooLow = (agg: AggConfig, aggIndex: number, group: AggConfig[]) => { +const calcAggIsTooLow = (agg: IAggConfig, aggIndex: number, group: IAggConfig[]) => { if (!agg.schema.mustBeFirst) { return false; } - const firstDifferentSchema = findIndex(group, (aggr: AggConfig) => { + const firstDifferentSchema = findIndex(group, (aggr: IAggConfig) => { return aggr.schema !== agg.schema; }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_state.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_state.tsx index b06ca1c2ce57a..d022297ae72b3 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_state.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_state.tsx @@ -17,7 +17,7 @@ * under the License. */ -import { AggConfig } from '../legacy_imports'; +import { IAggConfig } from '../legacy_imports'; export enum AGGS_ACTION_KEYS { TOUCHED = 'aggsTouched', @@ -52,7 +52,7 @@ function aggGroupReducer(state: AggsState, action: AggsAction): AggsState { } } -function initAggsState(group: AggConfig[]): AggsState { +function initAggsState(group: IAggConfig[]): AggsState { return group.reduce((state, agg) => { state[agg.id] = { touched: false, valid: true }; return state; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts index 01a41d3c412c2..c858fb62045ca 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts @@ -19,15 +19,16 @@ import { Field } from 'src/plugins/data/public'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfig, AggParam, EditorConfig } from '../legacy_imports'; +import { IAggConfig, AggParam } from '../legacy_imports'; import { ComboBoxGroupedOptions } from '../utils'; +import { EditorConfig } from './utils'; // NOTE: we cannot export the interface with export { InterfaceName } // as there is currently a bug on babel typescript transform plugin for it // https://github.com/babel/babel/issues/7641 // export interface AggParamCommonProps { - agg: AggConfig; + agg: IAggConfig; aggParam: P; disabled?: boolean; editorConfig: EditorConfig; @@ -36,7 +37,7 @@ export interface AggParamCommonProps { showValidation: boolean; state: VisState; value?: T; - metricAggs: AggConfig[]; + metricAggs: IAggConfig[]; } export interface AggParamEditorProps extends AggParamCommonProps { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx index d782c819c7c41..af851aa9b4418 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx @@ -23,7 +23,7 @@ import { mount, shallow } from 'enzyme'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { IndexPattern } from 'src/plugins/data/public'; import { DefaultEditorAggParams, DefaultEditorAggParamsProps } from './agg_params'; -import { AggConfig, AggGroupNames } from '../legacy_imports'; +import { IAggConfig, AggGroupNames } from '../legacy_imports'; const mockEditorConfig = { useNormalizedEsInterval: { hidden: false, fixedValue: false }, @@ -36,10 +36,8 @@ const mockEditorConfig = { }; jest.mock('ui/new_platform'); -jest.mock('ui/vis/config', () => ({ - editorConfigProviders: { - getConfigForAgg: jest.fn(() => mockEditorConfig), - }, +jest.mock('./utils', () => ({ + getEditorConfig: jest.fn(() => mockEditorConfig), })); jest.mock('./agg_params_helper', () => ({ getAggParamsToRender: jest.fn(() => ({ @@ -97,7 +95,7 @@ describe('DefaultEditorAggParams component', () => { schema: { title: '', }, - } as any) as AggConfig, + } as any) as IAggConfig, groupName: AggGroupNames.Metrics, formIsTouched: false, indexPattern: {} as IndexPattern, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx index 47e98f175ab73..e9583ab4cec79 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx @@ -23,14 +23,7 @@ import { i18n } from '@kbn/i18n'; import useUnmount from 'react-use/lib/useUnmount'; import { IndexPattern } from 'src/plugins/data/public'; -import { - AggConfig, - AggGroupNames, - editorConfigProviders, - FixedParam, - TimeIntervalParam, - EditorParamConfig, -} from '../legacy_imports'; +import { IAggConfig, AggGroupNames } from '../legacy_imports'; import { DefaultEditorAggSelect } from './agg_select'; import { DefaultEditorAggParam } from './agg_param'; @@ -46,6 +39,7 @@ import { initAggParamsState, } from './agg_params_state'; import { DefaultEditorCommonProps } from './agg_common_props'; +import { EditorParamConfig, TimeIntervalParam, FixedParam, getEditorConfig } from './utils'; const FIXED_VALUE_PROP = 'fixedValue'; const DEFAULT_PROP = 'default'; @@ -54,7 +48,7 @@ type EditorParamConfigType = EditorParamConfig & { }; export interface DefaultEditorAggParamsProps extends DefaultEditorCommonProps { - agg: AggConfig; + agg: IAggConfig; aggError?: string; aggIndex?: number; aggIsTooLow?: boolean; @@ -93,10 +87,12 @@ function DefaultEditorAggParams({ values: { schema: agg.schema.title }, }) : ''; - - const editorConfig = useMemo(() => editorConfigProviders.getConfigForAgg(indexPattern, agg), [ + const aggTypeName = agg.type?.name; + const fieldName = agg.params?.field?.name; + const editorConfig = useMemo(() => getEditorConfig(indexPattern, aggTypeName, fieldName), [ indexPattern, - agg, + aggTypeName, + fieldName, ]); const params = useMemo(() => getAggParamsToRender({ agg, editorConfig, metricAggs, state }), [ agg, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts index 6f584b4329500..f3bee80baa1ba 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts @@ -17,22 +17,16 @@ * under the License. */ -import { IndexPattern, Field } from 'src/plugins/data/public'; +import { IndexPattern } from 'src/plugins/data/public'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { - AggConfig, - AggType, - AggGroupNames, - BUCKET_TYPES, - IndexedArray, - EditorConfig, -} from '../legacy_imports'; +import { IAggConfig, IAggType, AggGroupNames, BUCKET_TYPES } from '../legacy_imports'; import { getAggParamsToRender, getAggTypeOptions, isInvalidParamsTouched, } from './agg_params_helper'; import { FieldParamEditor, OrderByParamEditor } from './controls'; +import { EditorConfig } from './utils'; jest.mock('../utils', () => ({ groupAndSortBy: jest.fn(() => ['indexedFields']), @@ -42,10 +36,10 @@ jest.mock('ui/new_platform'); describe('DefaultEditorAggParams helpers', () => { describe('getAggParamsToRender', () => { - let agg: AggConfig; + let agg: IAggConfig; let editorConfig: EditorConfig; const state = {} as VisState; - const metricAggs: AggConfig[] = []; + const metricAggs: IAggConfig[] = []; const emptyParams = { basic: [], advanced: [], @@ -57,14 +51,14 @@ describe('DefaultEditorAggParams helpers', () => { params: [{ name: 'interval' }], }, schema: {}, - } as AggConfig; + } as IAggConfig; const params = getAggParamsToRender({ agg, editorConfig, metricAggs, state }); expect(params).toEqual(emptyParams); }); it('should not create any param if there is no agg type', () => { - agg = {} as AggConfig; + agg = {} as IAggConfig; const params = getAggParamsToRender({ agg, editorConfig, metricAggs, state }); expect(params).toEqual(emptyParams); @@ -75,7 +69,7 @@ describe('DefaultEditorAggParams helpers', () => { type: { params: [{ name: 'interval' }], }, - } as AggConfig; + } as IAggConfig; editorConfig = { interval: { hidden: true, @@ -94,7 +88,7 @@ describe('DefaultEditorAggParams helpers', () => { schema: { hideCustomLabel: true, }, - } as AggConfig; + } as IAggConfig; const params = getAggParamsToRender({ agg, editorConfig, metricAggs, state }); expect(params).toEqual(emptyParams); @@ -111,8 +105,10 @@ describe('DefaultEditorAggParams helpers', () => { name: 'field', type: 'field', filterFieldTypes, - getAvailableFields: jest.fn((fields: IndexedArray) => - fields.filter(({ type }) => filterFieldTypes.includes(type)) + getAvailableFields: jest.fn((aggConfig: IAggConfig) => + aggConfig + .getIndexPattern() + .fields.filter(({ type }) => filterFieldTypes.includes(type)) ), }, { @@ -131,7 +127,7 @@ describe('DefaultEditorAggParams helpers', () => { orderBy: 'orderBy', field: 'field', }, - } as any) as AggConfig; + } as any) as IAggConfig; const params = getAggParamsToRender({ agg, editorConfig, metricAggs, state }); expect(params).toEqual({ @@ -166,14 +162,14 @@ describe('DefaultEditorAggParams helpers', () => { describe('getAggTypeOptions', () => { it('should return agg type options grouped by subtype', () => { const indexPattern = {} as IndexPattern; - const aggs = getAggTypeOptions({} as AggConfig, indexPattern, 'metrics'); + const aggs = getAggTypeOptions({} as IAggConfig, indexPattern, 'metrics'); expect(aggs).toEqual(['indexedFields']); }); }); describe('isInvalidParamsTouched', () => { - let aggType: AggType; + let aggType: IAggType; const aggTypeState = { touched: false, valid: true, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts index 21154bd7ad603..124c41a50c0df 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts @@ -29,17 +29,17 @@ import { aggTypeFilters, aggTypeFieldFilters, aggTypes, - AggConfig, + IAggConfig, AggParam, - FieldParamType, - AggType, - EditorConfig, + IFieldParamType, + IAggType, } from '../legacy_imports'; +import { EditorConfig } from './utils'; interface ParamInstanceBase { - agg: AggConfig; + agg: IAggConfig; editorConfig: EditorConfig; - metricAggs: AggConfig[]; + metricAggs: IAggConfig[]; state: VisState; } @@ -73,9 +73,7 @@ function getAggParamsToRender({ agg, editorConfig, metricAggs, state }: ParamIns } // if field param exists, compute allowed fields if (param.type === 'field') { - const availableFields: Field[] = (param as FieldParamType).getAvailableFields( - agg.getIndexPattern().fields - ); + const availableFields: Field[] = (param as IFieldParamType).getAvailableFields(agg); fields = aggTypeFieldFilters.filter(availableFields, agg); indexedFields = groupAndSortBy(fields, 'type', 'name'); @@ -117,10 +115,10 @@ function getAggParamsToRender({ agg, editorConfig, metricAggs, state }: ParamIns } function getAggTypeOptions( - agg: AggConfig, + agg: IAggConfig, indexPattern: IndexPattern, groupName: string -): ComboBoxGroupedOptions { +): ComboBoxGroupedOptions { const aggTypeOptions = aggTypeFilters.filter((aggTypes as any)[groupName], indexPattern, agg); return groupAndSortBy(aggTypeOptions as any[], 'subtype', 'title'); } @@ -135,7 +133,7 @@ function getAggTypeOptions( * @param aggParams State of aggregation parameters. */ function isInvalidParamsTouched( - aggType: AggType, + aggType: IAggType, aggTypeState: AggTypeState, aggParams: AggParamsState ) { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx index 2a9c74521e525..0ec19bfa1b843 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx @@ -24,20 +24,20 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { IndexPattern } from 'src/plugins/data/public'; -import { AggType, documentationLinks } from '../legacy_imports'; +import { IAggType, documentationLinks } from '../legacy_imports'; import { ComboBoxGroupedOptions } from '../utils'; import { AGG_TYPE_ACTION_KEYS, AggTypeAction } from './agg_params_state'; interface DefaultEditorAggSelectProps { aggError?: string; - aggTypeOptions: ComboBoxGroupedOptions; + aggTypeOptions: ComboBoxGroupedOptions; id: string; indexPattern: IndexPattern; showValidation: boolean; isSubAggregation: boolean; - value: AggType; + value: IAggType; onChangeAggType: React.Dispatch; - setValue: (aggType: AggType) => void; + setValue: (aggType: IAggType) => void; } function DefaultEditorAggSelect({ @@ -51,7 +51,7 @@ function DefaultEditorAggSelect({ isSubAggregation, onChangeAggType, }: DefaultEditorAggSelectProps) { - const selectedOptions: ComboBoxGroupedOptions = value + const selectedOptions: ComboBoxGroupedOptions = value ? [{ label: value.title, target: value }] : []; @@ -104,7 +104,7 @@ function DefaultEditorAggSelect({ (options: EuiComboBoxOptionProps[]) => { const selectedOption = get(options, '0.target'); if (selectedOption) { - setValue(selectedOption as AggType); + setValue(selectedOption as IAggType); } }, [setValue] diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_control_props.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_control_props.tsx index c8b5196d3b299..7f04b851902de 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_control_props.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_control_props.tsx @@ -18,11 +18,11 @@ */ import { VisParams } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; import { DefaultEditorAggCommonProps } from '../agg_common_props'; export interface AggControlProps { - agg: AggConfig; + agg: IAggConfig; editorStateParams: VisParams; setAggParamValue: DefaultEditorAggCommonProps['setAggParamValue']; setStateParamValue: DefaultEditorAggCommonProps['setStateParamValue']; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_utils.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_utils.test.tsx index 5c69fd0f1c091..0b847e3747b30 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_utils.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_utils.test.tsx @@ -20,7 +20,7 @@ import React, { FunctionComponent } from 'react'; import { mount, ReactWrapper } from 'enzyme'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; import { safeMakeLabel, useAvailableOptions, @@ -57,7 +57,7 @@ const metricAggs = [ return 'avg'; }, }, -] as AggConfig[]; +] as IAggConfig[]; const incompatibleAggs = [ { @@ -74,7 +74,7 @@ const incompatibleAggs = [ return 'percentiles'; }, }, -] as AggConfig[]; +] as IAggConfig[]; const aggFilter = ['!top_hits', '!percentiles']; describe('Aggregations utils', () => { @@ -222,7 +222,7 @@ describe('Aggregations utils', () => { }); test('should not fail and return a safety string if makeLabel func is not exist', () => { - const label = safeMakeLabel({} as AggConfig); + const label = safeMakeLabel({} as IAggConfig); expect(label).toEqual(expect.any(String)); }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx index e43304fe07347..636ef8f872d0e 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx @@ -26,7 +26,7 @@ import { Field } from 'src/plugins/data/public'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { ComboBoxGroupedOptions } from '../../utils'; import { FieldParamEditor, FieldParamEditorProps } from './field'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; function callComboBoxOnChange(comp: ReactWrapper, value: any = []) { const comboBoxProps: EuiComboBoxProps = comp.find(EuiComboBox).props(); @@ -64,7 +64,7 @@ describe('FieldParamEditor component', () => { ]; defaultProps = { - agg: {} as AggConfig, + agg: {} as IAggConfig, aggParam: { name: 'field', type: 'field', @@ -80,7 +80,7 @@ describe('FieldParamEditor component', () => { setValidity, setTouched, state: {} as VisState, - metricAggs: [] as AggConfig[], + metricAggs: [] as IAggConfig[], }; }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx index 38c55e8fe3f24..f374353afabec 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx @@ -24,7 +24,7 @@ import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Field } from 'src/plugins/data/public'; -import { AggConfig, AggParam, FieldParamType } from '../../legacy_imports'; +import { AggParam, IAggConfig, IFieldParamType } from '../../legacy_imports'; import { formatListAsProse, parseCommaSeparatedList, useValidation } from './utils'; import { AggParamEditorProps } from '../agg_param_props'; import { ComboBoxGroupedOptions } from '../../utils'; @@ -126,9 +126,10 @@ function FieldParamEditor({ ); } -function getFieldTypesString(agg: AggConfig) { +function getFieldTypesString(agg: IAggConfig) { const param = - get(agg, 'type.params', []).find((p: AggParam) => p.name === 'field') || ({} as FieldParamType); + get(agg, 'type.params', []).find((p: AggParam) => p.name === 'field') || + ({} as IFieldParamType); return formatListAsProse(parseCommaSeparatedList(param.filterFieldTypes), { inclusive: false }); } diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/filter.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/filter.tsx index 38c5b552553ae..3622b27bad403 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/filter.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/filter.tsx @@ -22,7 +22,7 @@ import { EuiForm, EuiButtonIcon, EuiFieldText, EuiFormRow, EuiSpacer } from '@el import { i18n } from '@kbn/i18n'; import { Query, QueryStringInput } from '../../../../../../plugins/data/public'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; interface FilterRowProps { id: string; @@ -34,7 +34,7 @@ interface FilterRowProps { dataTestSubj: string; onChangeValue(id: string, query: Query, label: string): void; onRemoveFilter(id: string): void; - agg: AggConfig; + agg: IAggConfig; } function FilterRow({ diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/metric_agg.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/metric_agg.test.tsx index 9b6fd204e7207..cf7af1aa5cb3a 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/metric_agg.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/metric_agg.test.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; import { DEFAULT_OPTIONS, aggFilter, MetricAggParamEditor } from './metric_agg'; jest.mock('./utils', () => ({ @@ -44,7 +44,7 @@ const agg = { makeLabel() { return 'cumulative_sum'; }, -} as AggConfig; +} as IAggConfig; const metricAggs = [ agg, @@ -69,7 +69,7 @@ const metricAggs = [ return 'max'; }, }, -] as AggConfig[]; +] as IAggConfig[]; describe('MetricAggParamEditor', () => { let defaultProps: Partial>; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/order_agg.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/order_agg.tsx index 6bb9ad334d149..10679b578d54e 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/order_agg.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/order_agg.tsx @@ -20,7 +20,7 @@ import React, { useEffect } from 'react'; import { EuiSpacer } from '@elastic/eui'; -import { AggParamType, AggConfig, AggGroupNames } from '../../legacy_imports'; +import { AggParamType, IAggConfig, AggGroupNames } from '../../legacy_imports'; import { useSubAggParamsHandlers } from './utils'; import { AggParamEditorProps } from '../agg_param_props'; import { DefaultEditorAggParams } from '../agg_params'; @@ -35,7 +35,7 @@ function OrderAggParamEditor({ setValue, setValidity, setTouched, -}: AggParamEditorProps) { +}: AggParamEditorProps) { const orderBy = agg.params.orderBy; useEffect(() => { @@ -51,7 +51,7 @@ function OrderAggParamEditor({ const { onAggTypeChange, setAggParamValue } = useSubAggParamsHandlers( agg, aggParam, - value as AggConfig, + value as IAggConfig, setValue ); @@ -63,7 +63,7 @@ function OrderAggParamEditor({ <> ) { +}: AggParamEditorProps) { useEffect(() => { // we aren't creating a custom aggConfig if (agg.params.metricAgg !== 'custom') { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/sub_metric.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/sub_metric.tsx index 9898d943870bc..45ff0610d88ed 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/sub_metric.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/sub_metric.tsx @@ -21,7 +21,7 @@ import React, { useEffect } from 'react'; import { EuiFormLabel, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { AggParamType, AggConfig, AggGroupNames } from '../../legacy_imports'; +import { AggParamType, IAggConfig, AggGroupNames } from '../../legacy_imports'; import { useSubAggParamsHandlers } from './utils'; import { AggParamEditorProps } from '../agg_param_props'; import { DefaultEditorAggParams } from '../agg_params'; @@ -35,7 +35,7 @@ function SubMetricParamEditor({ setValue, setValidity, setTouched, -}: AggParamEditorProps) { +}: AggParamEditorProps) { const metricTitle = i18n.translate('visDefaultEditor.controls.metrics.metricTitle', { defaultMessage: 'Metric', }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts b/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts index 4e811f4543412..4280f85c901d7 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts @@ -18,14 +18,15 @@ */ import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfig, AggParam, EditorConfig } from '../../legacy_imports'; +import { IAggConfig, AggParam } from '../../legacy_imports'; +import { EditorConfig } from '../utils'; export const aggParamCommonPropsMock = { - agg: {} as AggConfig, + agg: {} as IAggConfig, aggParam: {} as AggParam, editorConfig: {} as EditorConfig, formIsTouched: false, - metricAggs: [] as AggConfig[], + metricAggs: [] as IAggConfig[], state: {} as VisState, showValidation: false, }; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/time_interval.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/time_interval.tsx index 6168890c2f2da..5da0d6462a8ba 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/time_interval.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/time_interval.tsx @@ -107,7 +107,7 @@ function TimeIntervalParamEditor({ const onChange = (opts: EuiComboBoxOptionProps[]) => { const selectedOpt: ComboBoxOption = get(opts, '0'); - setValue(selectedOpt ? selectedOpt.key : selectedOpt); + setValue(selectedOpt ? selectedOpt.key : ''); if (selectedOpt) { agg.write(); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.test.tsx index b0c3fe00606aa..4ce0712040bd5 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.test.tsx @@ -25,10 +25,10 @@ import { TopAggregateParamEditorProps, } from './top_aggregate'; import { aggParamCommonPropsMock } from './test_utils'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; describe('TopAggregateParamEditor', () => { - let agg: AggConfig; + let agg: IAggConfig; let aggParam: any; let defaultProps: TopAggregateParamEditorProps; let options: AggregateValueProp[]; @@ -37,17 +37,17 @@ describe('TopAggregateParamEditor', () => { options = [ { text: 'Min', - isCompatible: jest.fn((aggr: AggConfig) => aggr.params.field.type === 'number'), + isCompatible: jest.fn((aggr: IAggConfig) => aggr.params.field.type === 'number'), value: 'min', }, { text: 'Max', - isCompatible: jest.fn((aggr: AggConfig) => aggr.params.field.type === 'number'), + isCompatible: jest.fn((aggr: IAggConfig) => aggr.params.field.type === 'number'), value: 'max', }, { text: 'Average', - isCompatible: jest.fn((aggr: AggConfig) => aggr.params.field.type === 'string'), + isCompatible: jest.fn((aggr: IAggConfig) => aggr.params.field.type === 'string'), value: 'average', }, ]; @@ -69,7 +69,7 @@ describe('TopAggregateParamEditor', () => { }, }, getAggParams: jest.fn(() => [{ name: 'aggregate', options }]), - } as any) as AggConfig; + } as any) as IAggConfig; defaultProps = { ...aggParamCommonPropsMock, agg, @@ -150,7 +150,7 @@ describe('TopAggregateParamEditor', () => { type: 'string', }, }, - } as AggConfig; + } as IAggConfig; comp.setProps({ agg }); @@ -165,7 +165,7 @@ describe('TopAggregateParamEditor', () => { type: 'date', }, }, - } as AggConfig; + } as IAggConfig; comp.setProps({ agg }); @@ -179,7 +179,7 @@ describe('TopAggregateParamEditor', () => { type: 'string', }, }, - } as AggConfig; + } as IAggConfig; comp.setProps({ agg, value: undefined }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.tsx index 338e2fe463a80..346dfc0156f07 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.tsx @@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { - AggConfig, + IAggConfig, AggParam, OptionedValueProp, OptionedParamEditorProps, @@ -32,13 +32,13 @@ import { import { AggParamEditorProps } from '../agg_param_props'; export interface AggregateValueProp extends OptionedValueProp { - isCompatible(aggConfig: AggConfig): boolean; + isCompatible(aggConfig: IAggConfig): boolean; } export type TopAggregateParamEditorProps = AggParamEditorProps & OptionedParamEditorProps; -export function getCompatibleAggs(agg: AggConfig): AggregateValueProp[] { +export function getCompatibleAggs(agg: IAggConfig): AggregateValueProp[] { const { options = [] } = agg .getAggParams() .find(({ name }: AggParam) => name === 'aggregate') as OptionedParamType; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/agg_utils.ts b/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/agg_utils.ts index 4c8ba23e63268..8aeae488942cd 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/agg_utils.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/agg_utils.ts @@ -20,7 +20,7 @@ import { useEffect, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import { AggConfig } from '../../../legacy_imports'; +import { IAggConfig } from '../../../legacy_imports'; type AggFilter = string[]; @@ -43,7 +43,7 @@ function useCompatibleAggCallback(aggFilter: AggFilter) { function useFallbackMetric( setValue: (value?: string) => void, aggFilter: AggFilter, - metricAggs?: AggConfig[], + metricAggs?: IAggConfig[], value?: string, fallbackValue?: string ) { @@ -69,7 +69,7 @@ function useFallbackMetric( */ function useAvailableOptions( aggFilter: AggFilter, - metricAggs: AggConfig[] = [], + metricAggs: IAggConfig[] = [], defaultOptions: Array<{ text: string; value: string }> = [] ) { const isCompatibleAgg = useCompatibleAggCallback(aggFilter); @@ -107,7 +107,7 @@ function useValidation(setValidity: (isValid: boolean) => void, isValid: boolean }, [isValid, setValidity]); } -function safeMakeLabel(agg: AggConfig): string { +function safeMakeLabel(agg: IAggConfig): string { try { return agg.makeLabel(); } catch (e) { @@ -118,7 +118,7 @@ function safeMakeLabel(agg: AggConfig): string { } function isCompatibleAggregation(aggFilter: string[]) { - return (agg: AggConfig) => { + return (agg: IAggConfig) => { return !aggFilter.includes(`!${agg.type.name}`); }; } diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/use_handlers.ts b/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/use_handlers.ts index c2da648edcf81..c7816d5a9d305 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/use_handlers.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/use_handlers.ts @@ -19,14 +19,14 @@ import { useCallback } from 'react'; -import { AggConfig, AggParamType } from '../../../legacy_imports'; +import { IAggConfig, AggParamType } from '../../../legacy_imports'; -type SetValue = (value?: AggConfig) => void; +type SetValue = (value?: IAggConfig) => void; function useSubAggParamsHandlers( - agg: AggConfig, + agg: IAggConfig, aggParam: AggParamType, - subAgg: AggConfig, + subAgg: IAggConfig, setValue: SetValue ) { const setAggParamValue = useCallback( diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx index c7597ef43dfa6..efd17f02a0e09 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx @@ -23,11 +23,11 @@ import { EuiSpacer } from '@elastic/eui'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { - AggConfig, + IAggConfig, AggGroupNames, ISchemas, parentPipelineType, - MetricAggType, + IMetricAggType, } from '../../legacy_imports'; import { DefaultEditorAggGroup } from '../agg_group'; import { @@ -45,7 +45,7 @@ export interface DefaultEditorDataTabProps { dispatch: React.Dispatch; formIsTouched: boolean; isTabSelected: boolean; - metricAggs: AggConfig[]; + metricAggs: IAggConfig[]; schemas: ISchemas; state: VisState; setTouched(isTouched: boolean): void; @@ -67,7 +67,7 @@ function DefaultEditorDataTab({ () => findLast( metricAggs, - ({ type }: { type: MetricAggType }) => type.subtype === parentPipelineType + ({ type }: { type: IMetricAggType }) => type.subtype === parentPipelineType ), [metricAggs] ); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/actions.ts b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/actions.ts index 5738916d2ff80..93fa1083bebf9 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/actions.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/actions.ts @@ -18,7 +18,7 @@ */ import { Vis, VisParams } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfig, Schema } from '../../../legacy_imports'; +import { IAggConfig, Schema } from '../../../legacy_imports'; import { EditorStateActionTypes } from './constants'; export interface ActionType { @@ -26,14 +26,14 @@ export interface ActionType { payload: P; } -type AggId = AggConfig['id']; -type AggParams = AggConfig['params']; +type AggId = IAggConfig['id']; +type AggParams = IAggConfig['params']; type AddNewAgg = ActionType; type DiscardChanges = ActionType; type ChangeAggType = ActionType< EditorStateActionTypes.CHANGE_AGG_TYPE, - { aggId: AggId; value: AggConfig['type'] } + { aggId: AggId; value: IAggConfig['type'] } >; type SetAggParamValue = ActionType< EditorStateActionTypes.SET_AGG_PARAM_VALUE, @@ -50,11 +50,11 @@ type SetStateParamValue = ActionTyp type RemoveAgg = ActionType; type ReorderAggs = ActionType< EditorStateActionTypes.REORDER_AGGS, - { sourceAgg: AggConfig; destinationAgg: AggConfig } + { sourceAgg: IAggConfig; destinationAgg: IAggConfig } >; type ToggleEnabledAgg = ActionType< EditorStateActionTypes.TOGGLE_ENABLED_AGG, - { aggId: AggId; enabled: AggConfig['enabled'] } + { aggId: AggId; enabled: IAggConfig['enabled'] } >; type UpdateStateParams = ActionType< EditorStateActionTypes.UPDATE_STATE_PARAMS, @@ -75,7 +75,7 @@ export type EditorAction = export interface EditorActions { addNewAgg(schema: Schema): AddNewAgg; discardChanges(vis: Vis): DiscardChanges; - changeAggType(aggId: AggId, value: AggConfig['type']): ChangeAggType; + changeAggType(aggId: AggId, value: IAggConfig['type']): ChangeAggType; setAggParamValue( aggId: AggId, paramName: T, @@ -86,8 +86,8 @@ export interface EditorActions { value: AggParams[T] ): SetStateParamValue; removeAgg(aggId: AggId): RemoveAgg; - reorderAggs(sourceAgg: AggConfig, destinationAgg: AggConfig): ReorderAggs; - toggleEnabledAgg(aggId: AggId, enabled: AggConfig['enabled']): ToggleEnabledAgg; + reorderAggs(sourceAgg: IAggConfig, destinationAgg: IAggConfig): ReorderAggs; + toggleEnabledAgg(aggId: AggId, enabled: IAggConfig['enabled']): ToggleEnabledAgg; updateStateParams(params: VisParams): UpdateStateParams; } diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts index 8e1cfd6bc9c13..851263f0ed702 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts @@ -20,7 +20,7 @@ import { cloneDeep } from 'lodash'; import { Vis, VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfigs, AggConfig, AggGroupNames, move } from '../../../legacy_imports'; +import { AggConfigs, IAggConfig, AggGroupNames, move } from '../../../legacy_imports'; import { EditorStateActionTypes } from './constants'; import { getEnabledMetricAggsCount } from '../../agg_group_helper'; import { EditorAction } from './actions'; @@ -32,7 +32,7 @@ function initEditorState(vis: Vis) { function editorStateReducer(state: VisState, action: EditorAction): VisState { switch (action.type) { case EditorStateActionTypes.ADD_NEW_AGG: { - const aggConfig = state.aggs.createAggConfig(action.payload as AggConfig, { + const aggConfig = state.aggs.createAggConfig(action.payload as IAggConfig, { addToAggConfigs: false, }); aggConfig.brandNew = true; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/utils/editor_config.ts b/src/legacy/core_plugins/vis_default_editor/public/components/utils/editor_config.ts new file mode 100644 index 0000000000000..80a64b7289f8c --- /dev/null +++ b/src/legacy/core_plugins/vis_default_editor/public/components/utils/editor_config.ts @@ -0,0 +1,135 @@ +/* + * 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 { IndexPattern } from 'src/plugins/data/public'; + +/** + * A hidden parameter can be hidden from the UI completely. + */ +interface Param { + hidden?: boolean; + help?: string; +} + +/** + * A fixed parameter has a fixed value for a specific field. + * It can optionally also be hidden. + */ +export type FixedParam = Partial & { + fixedValue: any; +}; + +/** + * Numeric interval parameters must always be set in the editor to a multiple of + * the specified base. It can optionally also be hidden. + */ +export type NumericIntervalParam = Partial & { + base: number; +}; + +/** + * Time interval parameters must always be set in the editor to a multiple of + * the specified base. It can optionally also be hidden. + */ +export type TimeIntervalParam = Partial & { + default: string; + timeBase: string; +}; + +export type EditorParamConfig = NumericIntervalParam | TimeIntervalParam | FixedParam | Param; + +export interface EditorConfig { + [paramName: string]: EditorParamConfig; +} + +export function getEditorConfig( + indexPattern: IndexPattern, + aggTypeName: string, + fieldName: string +): EditorConfig { + const aggRestrictions = indexPattern.getAggregationRestrictions(); + + if (!aggRestrictions || !aggTypeName || !fieldName) { + return {}; + } + + // Exclude certain param options for terms: + // otherBucket, missingBucket, orderBy, orderAgg + if (aggTypeName === 'terms') { + return { + otherBucket: { + hidden: true, + }, + missingBucket: { + hidden: true, + }, + }; + } + + const fieldAgg = aggRestrictions[aggTypeName] && aggRestrictions[aggTypeName][fieldName]; + + if (!fieldAgg) { + return {}; + } + + // Set interval and base interval for histograms based on agg restrictions + if (aggTypeName === 'histogram') { + const interval = fieldAgg.interval; + return interval + ? { + intervalBase: { + fixedValue: interval, + }, + interval: { + base: interval, + help: i18n.translate('visDefaultEditor.editorConfig.histogram.interval.helpText', { + defaultMessage: 'Must be a multiple of configuration interval: {interval}', + values: { interval }, + }), + }, + } + : {}; + } + + // Set date histogram time zone based on agg restrictions + if (aggTypeName === 'date_histogram') { + // Interval is deprecated on date_histogram rollups, but may still be present + // See https://github.com/elastic/kibana/pull/36310 + const interval = fieldAgg.calendar_interval || fieldAgg.fixed_interval; + return { + useNormalizedEsInterval: { + fixedValue: false, + }, + interval: { + default: interval, + timeBase: interval, + help: i18n.translate( + 'visDefaultEditor.editorConfig.dateHistogram.customInterval.helpText', + { + defaultMessage: 'Must be a multiple of configuration interval: {interval}', + values: { interval }, + } + ), + }, + }; + } + + return {}; +} diff --git a/src/plugins/kibana_react/public/saved_objects/index.ts b/src/legacy/core_plugins/vis_default_editor/public/components/utils/index.ts similarity index 90% rename from src/plugins/kibana_react/public/saved_objects/index.ts rename to src/legacy/core_plugins/vis_default_editor/public/components/utils/index.ts index ade80d2cd2a92..14570356103b1 100644 --- a/src/plugins/kibana_react/public/saved_objects/index.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/utils/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export * from './saved_object_finder'; -export * from './saved_object_save_modal'; +export * from './editor_config'; diff --git a/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts b/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts index 5c617f3dc8681..b7fd6b1e9ebb6 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts @@ -20,39 +20,36 @@ /* `ui/agg_types` dependencies */ export { AggType, - AggConfig, + IAggType, + IAggConfig, AggConfigs, + IAggConfigs, AggParam, AggGroupNames, aggGroupNamesMap, aggTypes, FieldParamType, + IFieldParamType, BUCKET_TYPES, METRIC_TYPES, ISchemas, Schema, termsAggFilter, } from 'ui/agg_types'; -export { aggTypeFilters, propFilter } from 'ui/agg_types/filter'; -export { aggTypeFieldFilters } from 'ui/agg_types/param_types/filter'; -export { AggParamType } from 'ui/agg_types/param_types/agg'; -export { MetricAggType } from 'ui/agg_types/metrics/metric_agg_type'; -export { parentPipelineType } from 'ui/agg_types/metrics/lib/parent_pipeline_agg_helper'; -export { siblingPipelineType } from 'ui/agg_types/metrics/lib/sibling_pipeline_agg_helper'; -export { isType, isStringType } from 'ui/agg_types/buckets/migrate_include_exclude_format'; -export { - OptionedValueProp, - OptionedParamEditorProps, - OptionedParamType, -} from 'ui/agg_types/param_types/optioned'; -export { isValidJson, isValidInterval } from 'ui/agg_types/utils'; -export { AggParamOption } from 'ui/agg_types/agg_params'; -export { CidrMask } from 'ui/agg_types/buckets/lib/cidr_mask'; +export { aggTypeFilters, propFilter } from 'ui/agg_types'; +export { aggTypeFieldFilters } from 'ui/agg_types'; +export { AggParamType } from 'ui/agg_types'; +export { MetricAggType, IMetricAggType } from 'ui/agg_types'; +export { parentPipelineType } from 'ui/agg_types'; +export { siblingPipelineType } from 'ui/agg_types'; +export { isType, isStringType } from 'ui/agg_types'; +export { OptionedValueProp, OptionedParamEditorProps, OptionedParamType } from 'ui/agg_types'; +export { isValidJson, isValidInterval } from 'ui/agg_types'; +export { AggParamOption } from 'ui/agg_types'; +export { CidrMask } from 'ui/agg_types'; export { PersistedState } from 'ui/persisted_state'; -export { IndexedArray } from 'ui/indexed_array'; export { getDocLink } from 'ui/documentation_links'; export { documentationLinks } from 'ui/documentation_links/documentation_links'; export { move } from 'ui/utils/collection'; export * from 'ui/vis/lib'; -export * from 'ui/vis/config'; diff --git a/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx b/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx index f51e359d99573..babcb59c6582e 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx @@ -17,11 +17,11 @@ * under the License. */ -import { AggConfigs, PersistedState } from './legacy_imports'; +import { IAggConfigs, PersistedState } from './legacy_imports'; import { Vis } from '../../visualizations/public'; export interface VisOptionsProps { - aggs: AggConfigs; + aggs: IAggConfigs; hasHistogramAgg: boolean; isTabSelected: boolean; stateParams: VisParamType; diff --git a/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts b/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts index c1832d5512817..60b675f50a342 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts @@ -17,7 +17,7 @@ * under the License. */ import { IndexPattern } from 'src/plugins/data/public'; -import { AggType, AggConfig, aggTypeFilters, propFilter } from './legacy_imports'; +import { IAggType, IAggConfig, aggTypeFilters, propFilter } from './legacy_imports'; const filterByName = propFilter('name'); @@ -25,7 +25,9 @@ const filterByName = propFilter('name'); * This filter checks the defined aggFilter in the schemas of that visualization * and limits available aggregations based on that. */ -aggTypeFilters.addFilter((aggType: AggType, indexPatterns: IndexPattern, aggConfig: AggConfig) => { - const doesSchemaAllowAggType = filterByName([aggType], aggConfig.schema.aggFilter).length !== 0; - return doesSchemaAllowAggType; -}); +aggTypeFilters.addFilter( + (aggType: IAggType, indexPatterns: IndexPattern, aggConfig: IAggConfig) => { + const doesSchemaAllowAggType = filterByName([aggType], aggConfig.schema.aggFilter).length !== 0; + return doesSchemaAllowAggType; + } +); diff --git a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts index 8a454957b7ab9..efa6c0029e6d1 100644 --- a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts @@ -19,7 +19,7 @@ export { npSetup, npStart } from 'ui/new_platform'; export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; -export { AggConfig, AggGroupNames, Schemas } from 'ui/agg_types'; +export { IAggConfig, AggGroupNames, Schemas } from 'ui/agg_types'; // @ts-ignore export { PrivateProvider } from 'ui/private/private'; diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts index 16181a3f70ff1..d8912975227bf 100644 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts +++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts @@ -27,7 +27,7 @@ import './table_vis.mock'; import StubIndexPattern from 'test_utils/stub_index_pattern'; import { getAngularModule } from './get_inner_angular'; import { initTableVisLegacyModule } from './table_vis_legacy_module'; -import { npStart, AggConfig, tabifyAggResponse } from './legacy_imports'; +import { npStart, IAggConfig, tabifyAggResponse } from './legacy_imports'; import { tableVisTypeDefinition } from './table_vis_type'; import { Vis } from '../../visualizations/public'; import { setup as visualizationsSetup } from '../../visualizations/public/np_ready/public/legacy'; @@ -148,7 +148,7 @@ describe('Table Vis - Controller', () => { // basically a parameterized beforeEach function initController(vis: Vis) { - vis.aggs.aggs.forEach((agg: AggConfig, i: number) => { + vis.aggs.aggs.forEach((agg: IAggConfig, i: number) => { agg.id = 'agg_' + (i + 1); }); diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/index_pattern.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/index_pattern.js index de8469adfb8a7..f6530eb22332a 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/index_pattern.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/index_pattern.js @@ -206,6 +206,7 @@ export const IndexPattern = ({ fields, prefix, onChange, disabled, model: _model })} > { const { name } = props; return () => { @@ -38,6 +38,7 @@ export function YesNo(props) {
({ const SERIES_PARAMS = 'seriesParams'; const VALUE_AXES = 'valueAxes'; -const aggCount: AggConfig = { +const aggCount: IAggConfig = { id: '1', type: { name: 'count' }, makeLabel: () => 'Count', -} as AggConfig; +} as IAggConfig; -const aggAverage: AggConfig = { +const aggAverage: IAggConfig = { id: '2', - type: { name: 'average' } as AggType, + type: { name: 'average' } as IAggType, makeLabel: () => 'Average', -} as AggConfig; +} as IAggConfig; const createAggs = (aggs: any[]) => ({ aggs, diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx index c4dcbfaa47265..cdc8996f3fdeb 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx @@ -21,7 +21,7 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { cloneDeep, uniq, get } from 'lodash'; import { EuiSpacer } from '@elastic/eui'; -import { AggConfig } from '../../../legacy_imports'; +import { IAggConfig } from '../../../legacy_imports'; import { BasicVislibParams, ValueAxis, SeriesParam, Axis } from '../../../types'; import { ValidationVisOptionsProps } from '../../common'; import { SeriesPanel } from './series_panel'; @@ -99,7 +99,7 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps) stateParams.valueAxes.forEach((axis, axisNumber) => { let newCustomLabel = ''; - const matchingSeries: AggConfig[] = []; + const matchingSeries: IAggConfig[] = []; series.forEach((serie, seriesIndex) => { if ((axisNumber === 0 && !serie.valueAxis) || serie.valueAxis === axis.id) { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts index df7278f2b761f..50a91df01de7c 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts @@ -17,7 +17,7 @@ * under the License. */ -export { AggType, AggConfig, AggGroupNames, Schemas } from 'ui/agg_types'; +export { AggType, AggGroupNames, IAggConfig, IAggType, Schemas } from 'ui/agg_types'; // @ts-ignore export { SimpleEmitter } from 'ui/utils/simple_emitter'; // @ts-ignore diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts b/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts index 46ade8ce465c0..719d69e21a826 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts +++ b/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; import { toastNotifications } from 'ui/notify'; -import { AggConfig } from 'ui/agg_types'; +import { IAggConfig } from 'ui/agg_types'; import { timefilter } from 'ui/timefilter'; import { Vis } from '../np_ready/public'; import { esFilters, Query, SearchSource, ISearchSource } from '../../../../../plugins/data/public'; @@ -42,7 +42,7 @@ interface QueryGeohashBoundsParams { * TODO: Remove this as a part of elastic/kibana#30593 */ export async function queryGeohashBounds(vis: Vis, params: QueryGeohashBoundsParams) { - const agg = vis.getAggConfig().aggs.find((a: AggConfig) => { + const agg = vis.getAggConfig().aggs.find((a: IAggConfig) => { return get(a, 'type.dslName') === 'geohash_grid'; }); diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx index e5836c1372068..03471174753fa 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx +++ b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx @@ -20,31 +20,24 @@ import { i18n } from '@kbn/i18n'; import { SavedObjectAttributes } from 'kibana/public'; import { - EmbeddableFactory, - ErrorEmbeddable, Container, + EmbeddableFactory, EmbeddableOutput, + ErrorEmbeddable, } from '../../../../../plugins/embeddable/public'; -import { showNewVisModal } from '../../../kibana/public/visualize'; import { SavedVisualizations } from '../../../kibana/public/visualize/np_ready/types'; import { DisabledLabEmbeddable } from './disabled_lab_embeddable'; import { getIndexPattern } from './get_index_pattern'; import { + VisSavedObject, VisualizeEmbeddable, VisualizeInput, VisualizeOutput, - VisSavedObject, } from './visualize_embeddable'; import { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; -import { - getUISettings, - getCapabilities, - getHttp, - getTypes, - getSavedObjects, - getUsageCollector, -} from '../np_ready/public/services'; +import { getCapabilities, getHttp, getTypes, getUISettings } from '../np_ready/public/services'; +import { showNewVisModal } from '../np_ready/public/wizard'; interface VisualizationAttributes extends SavedObjectAttributes { visState: string; @@ -157,16 +150,9 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory< public async create() { // TODO: This is a bit of a hack to preserve the original functionality. Ideally we will clean this up // to allow for in place creation of visualizations without having to navigate away to a new URL. - showNewVisModal( - getTypes(), - { - editorParams: ['addToDashboard'], - }, - getHttp().basePath.prepend, - getUISettings(), - getSavedObjects(), - getUsageCollector() - ); + showNewVisModal({ + editorParams: ['addToDashboard'], + }); return undefined; } } diff --git a/src/legacy/core_plugins/visualizations/public/index.scss b/src/legacy/core_plugins/visualizations/public/index.scss index 957d06be4daf0..748945eabd331 100644 --- a/src/legacy/core_plugins/visualizations/public/index.scss +++ b/src/legacy/core_plugins/visualizations/public/index.scss @@ -1,3 +1,4 @@ @import 'src/legacy/ui/public/styles/styling_constants'; -@import './embeddable/_index'; +@import './embeddable/index'; +@import './np_ready/public/index'; diff --git a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts index 3088c4e67a3b7..5cff588d951b0 100644 --- a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts +++ b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts @@ -18,12 +18,13 @@ */ export { PersistedState } from '../../../ui/public/persisted_state'; -export { AggConfig } from '../../../ui/public/agg_types/agg_config'; -export { AggConfigs } from '../../../ui/public/agg_types/agg_configs'; export { + AggConfigs, + IAggConfig, + IAggConfigs, isDateHistogramBucketAggConfig, setBounds, -} from '../../../ui/public/agg_types/buckets/date_histogram'; +} from '../../../ui/public/agg_types'; export { createFormat } from '../../../ui/public/visualize/loader/pipeline_helpers/utilities'; export { I18nContext } from '../../../ui/public/i18n'; import chrome from '../../../ui/public/chrome'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/_index.scss b/src/legacy/core_plugins/visualizations/public/np_ready/public/_index.scss new file mode 100644 index 0000000000000..d87b6b004a511 --- /dev/null +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/_index.scss @@ -0,0 +1 @@ +@import 'wizard/index'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts index e733bad2c0127..d1017de35474a 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts @@ -27,11 +27,11 @@ import { Schemas, } from './build_pipeline'; import { Vis, VisState } from '..'; -import { AggConfig } from '../../../legacy_imports'; +import { IAggConfig } from '../../../legacy_imports'; import { searchSourceMock } from '../../../legacy_mocks'; jest.mock('ui/new_platform'); -jest.mock('ui/agg_types/buckets/date_histogram', () => ({ +jest.mock('ui/agg_types', () => ({ setBounds: () => {}, dateHistogramBucketAgg: () => {}, isDateHistogramBucketAggConfig: () => true, @@ -367,7 +367,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => { }); describe('buildVislibDimensions', () => { - let aggs: AggConfig[]; + let aggs: IAggConfig[]; let visState: any; let vis: Vis; let params: any; @@ -385,7 +385,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => { name: 'metric', }, params: {}, - } as AggConfig, + } as IAggConfig, ]; params = { @@ -453,7 +453,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => { it('with two numeric metrics, mixed normal and percent mode should have corresponding formatters', async () => { const aggConfig = aggs[0]; - aggs = [{ ...aggConfig } as AggConfig, { ...aggConfig, id: '5' } as AggConfig]; + aggs = [{ ...aggConfig } as IAggConfig, { ...aggConfig, id: '5' } as IAggConfig]; visState = { params: { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts index 6749a44b4d5b3..04a296a888e87 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts @@ -23,7 +23,7 @@ import moment from 'moment'; import { SerializedFieldFormat } from 'src/plugins/expressions/public'; import { ISearchSource } from 'src/plugins/data/public'; import { - AggConfig, + IAggConfig, setBounds, isDateHistogramBucketAggConfig, createFormat, @@ -85,7 +85,7 @@ const vislibCharts: string[] = [ ]; export const getSchemas = (vis: Vis, timeRange?: any): Schemas => { - const createSchemaConfig = (accessor: number, agg: AggConfig): SchemaConfig => { + const createSchemaConfig = (accessor: number, agg: IAggConfig): SchemaConfig => { if (isDateHistogramBucketAggConfig(agg)) { agg.params.timeRange = timeRange; setBounds(agg, true); @@ -130,10 +130,10 @@ export const getSchemas = (vis: Vis, timeRange?: any): Schemas => { const schemas: Schemas = { metric: [], }; - const responseAggs = vis.aggs.getResponseAggs().filter((agg: AggConfig) => agg.enabled); + const responseAggs = vis.aggs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled); const isHierarchical = vis.isHierarchical(); - const metrics = responseAggs.filter((agg: AggConfig) => agg.type.type === 'metrics'); - responseAggs.forEach((agg: AggConfig) => { + const metrics = responseAggs.filter((agg: IAggConfig) => agg.type.type === 'metrics'); + responseAggs.forEach((agg: IAggConfig) => { let skipMetrics = false; let schemaName = agg.schema ? agg.schema.name || agg.schema : null; if (typeof schemaName === 'object') { @@ -224,7 +224,7 @@ export const prepareDimension = (variable: string, data: any) => { const adjustVislibDimensionFormmaters = (vis: Vis, dimensions: { y: any[] }): void => { const visState = vis.getCurrentState(); const visConfig = visState.params; - const responseAggs = vis.aggs.getResponseAggs().filter((agg: AggConfig) => agg.enabled); + const responseAggs = vis.aggs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled); (dimensions.y || []).forEach(yDimension => { const yAgg = responseAggs[yDimension.accessor]; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts index fc85970b906ae..1063b1718b851 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts @@ -48,6 +48,7 @@ const createStartContract = (): VisualizationsStart => ({ getAliases: jest.fn(), }, getSavedVisualizationsLoader: jest.fn(), + showNewVisModal: jest.fn(), }); const createInstance = async () => { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts index 01059044b98c2..cbbeb7ff980a6 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts @@ -43,6 +43,7 @@ import { SavedObjectKibanaServicesWithVisualizations, } from '../../saved_visualizations'; import { SavedVisualizations } from '../../../../kibana/public/visualize/np_ready/types'; +import { showNewVisModal } from './wizard'; /** * Interface for this plugin's returned setup/start contracts. * @@ -55,6 +56,7 @@ export interface VisualizationsSetup { export interface VisualizationsStart { types: TypesStart; getSavedVisualizationsLoader: () => SavedVisualizations; + showNewVisModal: typeof showNewVisModal; } export interface VisualizationsSetupDeps { @@ -92,7 +94,7 @@ export class VisualizationsPlugin public setup( core: CoreSetup, { expressions, embeddable, usageCollection }: VisualizationsSetupDeps - ) { + ): VisualizationsSetup { setUISettings(core.uiSettings); setUsageCollector(usageCollection); @@ -107,7 +109,7 @@ export class VisualizationsPlugin }; } - public start(core: CoreStart, { data }: VisualizationsStartDeps) { + public start(core: CoreStart, { data }: VisualizationsStartDeps): VisualizationsStart { const types = this.types.start(); setI18n(core.i18n); setTypes(types); @@ -128,6 +130,7 @@ export class VisualizationsPlugin return { types, getSavedVisualizationsLoader: () => this.getSavedVisualizationsLoader(), + showNewVisModal, }; } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts index 6e6a2174d6ad1..71bf9bcf983ff 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts @@ -18,7 +18,7 @@ */ import { VisType } from './types'; -import { AggConfigs } from '../../legacy_imports'; +import { IAggConfigs } from '../../legacy_imports'; import { Status } from './legacy/update_status'; export interface Vis { @@ -39,7 +39,7 @@ export interface VisState { title: string; type: VisType; params: VisParams; - aggs: AggConfigs; + aggs: IAggConfigs; } export declare class VisualizationController { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js index 4f1526c20cb6f..0c2e5012df439 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js @@ -21,7 +21,7 @@ * @name Vis * * @description This class consists of aggs, params, listeners, title, and type. - * - Aggs: Instances of AggConfig. + * - Aggs: Instances of IAggConfig. * - Params: The settings in the Options tab. * * Not to be confused with vislib/vis.js. diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/__snapshots__/new_vis_modal.test.tsx.snap b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/__snapshots__/new_vis_modal.test.tsx.snap similarity index 99% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/__snapshots__/new_vis_modal.test.tsx.snap rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/__snapshots__/new_vis_modal.test.tsx.snap index 2dcf3ed0ea06f..b1c9e37218c58 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/__snapshots__/new_vis_modal.test.tsx.snap +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/__snapshots__/new_vis_modal.test.tsx.snap @@ -1154,7 +1154,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1` > New Visualization @@ -1344,7 +1344,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1` > Select a visualization type @@ -1718,7 +1718,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1`

Start creating your visualization by selecting a type for that visualization. @@ -2844,7 +2844,7 @@ exports[`NewVisModal should render as expected 1`] = ` > New Visualization @@ -3317,7 +3317,7 @@ exports[`NewVisModal should render as expected 1`] = ` > Select a visualization type @@ -3342,7 +3342,7 @@ exports[`NewVisModal should render as expected 1`] = `

Start creating your visualization by selecting a type for that visualization. diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/_dialog.scss b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/_dialog.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/_dialog.scss rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/_dialog.scss diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/_index.scss b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/_index.scss rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/index.ts similarity index 94% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/index.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/index.ts index 7a3fc63af5259..55ac9ddfb5ca8 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/index.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export { NewVisModal } from './new_vis_modal'; export { showNewVisModal } from './show_new_vis'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/new_vis_modal.test.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.test.tsx similarity index 96% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/new_vis_modal.test.tsx rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.test.tsx index 0ef1b711eafc8..0701b5042a4bd 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/new_vis_modal.test.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.test.tsx @@ -19,15 +19,7 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; - -import { VisType } from '../../legacy_imports'; -import { TypesStart } from '../../../../../visualizations/public/np_ready/public/types'; - -jest.mock('../../legacy_imports', () => ({ - State: () => null, - AppState: () => null, -})); - +import { TypesStart, VisType } from '../types'; import { NewVisModal } from './new_vis_modal'; import { SavedObjectsStart } from 'kibana/public'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.tsx similarity index 93% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/new_vis_modal.tsx rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.tsx index 082fc3bc36b6b..fe66d2e56c611 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/new_vis_modal.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.tsx @@ -24,14 +24,9 @@ import { i18n } from '@kbn/i18n'; import { METRIC_TYPE, UiStatsMetricType } from '@kbn/analytics'; import { IUiSettingsClient, SavedObjectsStart } from 'kibana/public'; -import { VisType } from '../../legacy_imports'; -import { VisualizeConstants } from '../visualize_constants'; import { SearchSelection } from './search_selection'; import { TypeSelection } from './type_selection'; -import { - TypesStart, - VisTypeAlias, -} from '../../../../../visualizations/public/np_ready/public/types'; +import { TypesStart, VisType, VisTypeAlias } from '../types'; import { UsageCollectionSetup } from '../../../../../../../plugins/usage_collection/public'; interface TypeSelectionProps { @@ -50,7 +45,9 @@ interface TypeSelectionState { visType?: VisType; } -const baseUrl = `#${VisualizeConstants.CREATE_PATH}?`; +// TODO: redirect logic is specific to visualise & dashboard +// but it is likely should be decoupled. e.g. handled by the container instead +const baseUrl = `#/visualize/create?`; class NewVisModal extends React.Component { public static defaultProps = { @@ -82,7 +79,7 @@ class NewVisModal extends React.Component void; @@ -42,13 +42,13 @@ export class SearchSelection extends React.Component { {' '} /{' '} @@ -59,7 +59,7 @@ export class SearchSelection extends React.Component { onChoose={this.props.onSearchSelected} showFilter noItemsMessage={i18n.translate( - 'kbn.visualize.newVisWizard.searchSelection.notFoundLabel', + 'visualizations.newVisWizard.searchSelection.notFoundLabel', { defaultMessage: 'No matching indices or saved searches found.', } @@ -69,7 +69,7 @@ export class SearchSelection extends React.Component { type: 'search', getIconForSavedObject: () => 'search', name: i18n.translate( - 'kbn.visualize.newVisWizard.searchSelection.savedObjectType.search', + 'visualizations.newVisWizard.searchSelection.savedObjectType.search', { defaultMessage: 'Saved search', } @@ -79,7 +79,7 @@ export class SearchSelection extends React.Component { type: 'index-pattern', getIconForSavedObject: () => 'indexPatternApp', name: i18n.translate( - 'kbn.visualize.newVisWizard.searchSelection.savedObjectType.indexPattern', + 'visualizations.newVisWizard.searchSelection.savedObjectType.indexPattern', { defaultMessage: 'Index pattern', } diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/show_new_vis.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/show_new_vis.tsx similarity index 63% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/show_new_vis.tsx rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/show_new_vis.tsx index 567b7e861ad8e..8ca846ee39499 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/show_new_vis.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/show_new_vis.tsx @@ -21,27 +21,22 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { I18nProvider } from '@kbn/i18n/react'; -import { IUiSettingsClient, SavedObjectsStart } from 'kibana/public'; import { NewVisModal } from './new_vis_modal'; -import { TypesStart } from '../../../../../visualizations/public/np_ready/public/types'; -import { UsageCollectionSetup } from '../../../../../../../plugins/usage_collection/public'; +import { getHttp, getSavedObjects, getTypes, getUISettings, getUsageCollector } from '../services'; -interface ShowNewVisModalParams { +export interface ShowNewVisModalParams { editorParams?: string[]; + onClose?: () => void; } -export function showNewVisModal( - visTypeRegistry: TypesStart, - { editorParams = [] }: ShowNewVisModalParams = {}, - addBasePath: (path: string) => string, - uiSettings: IUiSettingsClient, - savedObjects: SavedObjectsStart, - usageCollection?: UsageCollectionSetup -) { +export function showNewVisModal({ editorParams = [], onClose }: ShowNewVisModalParams = {}) { const container = document.createElement('div'); - const onClose = () => { + const handleClose = () => { ReactDOM.unmountComponentAtNode(container); document.body.removeChild(container); + if (onClose) { + onClose(); + } }; document.body.appendChild(container); @@ -49,13 +44,13 @@ export function showNewVisModal( ); diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/index.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/index.ts diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/new_vis_help.test.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.test.tsx similarity index 97% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/new_vis_help.test.tsx rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.test.tsx index a33a82c252fb3..138251beb9593 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/new_vis_help.test.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.test.tsx @@ -49,7 +49,7 @@ describe('NewVisHelp', () => {

diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/new_vis_help.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.tsx similarity index 93% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/new_vis_help.tsx rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.tsx index 2f7effb7a33c8..5068f43952c4e 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/new_vis_help.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.tsx @@ -21,7 +21,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React, { Fragment } from 'react'; import { EuiText, EuiButton } from '@elastic/eui'; import { VisTypeAliasListEntry } from './type_selection'; -import { VisTypeAlias } from '../../../../../../visualizations/public'; +import { VisTypeAlias } from '../../types'; interface Props { promotedTypes: VisTypeAliasListEntry[]; @@ -33,7 +33,7 @@ export function NewVisHelp(props: Props) {

diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/type_selection.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/type_selection.tsx similarity index 90% rename from src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/type_selection.tsx rename to src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/type_selection.tsx index 44da7cc8f2c45..574f5b3cccc99 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/wizard/type_selection/type_selection.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/type_selection.tsx @@ -34,13 +34,13 @@ import { EuiSpacer, EuiTitle, } from '@elastic/eui'; -import { VisType } from '../../../legacy_imports'; + import { memoizeLast } from '../../../../../../visualizations/public/np_ready/public/legacy/memoize'; import { VisTypeAlias } from '../../../../../../visualizations/public'; import { NewVisHelp } from './new_vis_help'; import { VisHelpText } from './vis_help_text'; import { VisTypeIcon } from './vis_type_icon'; -import { TypesStart } from '../../../../../../visualizations/public/np_ready/public/types'; +import { VisType, TypesStart } from '../../types'; export interface VisTypeListEntry extends VisType { highlighted: boolean; @@ -85,7 +85,7 @@ class TypeSelection extends React.Component @@ -107,7 +107,7 @@ class TypeSelection extends React.Component {query && (

@@ -207,26 +207,26 @@ class TypeSelection extends React.Component !schema.isHiddenType(type)); const importableAndExportableTypes = getImportableAndExportableTypes({ kbnServer, visibleTypes }); @@ -99,7 +100,7 @@ export function savedObjectsMixin(kbnServer, server) { server.route(createResolveImportErrorsRoute(prereqs, server, importableAndExportableTypes)); server.route(createLogLegacyImportRoute()); - const serializer = new SavedObjectsSerializer(schema); + const serializer = kbnServer.newPlatform.start.core.savedObjects.createSerializer(); const createRepository = (callCluster, extraTypes = []) => { if (typeof callCluster !== 'function') { @@ -118,10 +119,9 @@ export function savedObjectsMixin(kbnServer, server) { return new SavedObjectsRepository({ index: config.get('kibana.index'), - config, migrator, mappings, - schema, + typeRegistry, serializer, allowedTypes, callCluster, 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 691878cf66d27..9ca0374b959f6 100644 --- a/src/legacy/server/saved_objects/saved_objects_mixin.test.js +++ b/src/legacy/server/saved_objects/saved_objects_mixin.test.js @@ -22,6 +22,14 @@ import { savedObjectsMixin } from './saved_objects_mixin'; import { mockKibanaMigrator } from '../../../core/server/saved_objects/migrations/kibana/kibana_migrator.mock'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { savedObjectsClientProviderMock } from '../../../core/server/saved_objects/service/lib/scoped_client_provider.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { convertLegacyTypes } from '../../../core/server/saved_objects/utils'; +import { SavedObjectTypeRegistry } from '../../../core/server'; +import { coreMock } from '../../../core/server/mocks'; + +const mockConfig = { + get: jest.fn().mockReturnValue('anything'), +}; const savedObjectMappings = [ { @@ -61,7 +69,30 @@ const savedObjectMappings = [ }, ]; -const migrator = mockKibanaMigrator.create({ savedObjectMappings }); +const savedObjectSchemas = { + hiddentype: { + hidden: true, + }, + doc1: { + indexPattern: 'other-index', + }, +}; + +const savedObjectTypes = convertLegacyTypes( + { + savedObjectMappings, + savedObjectSchemas, + savedObjectMigrations: {}, + }, + mockConfig +); + +const typeRegistry = new SavedObjectTypeRegistry(); +savedObjectTypes.forEach(type => typeRegistry.registerType(type)); + +const migrator = mockKibanaMigrator.create({ + types: savedObjectTypes, +}); describe('Saved Objects Mixin', () => { let mockKbnServer; @@ -113,7 +144,17 @@ describe('Saved Objects Mixin', () => { }; mockKbnServer = { newPlatform: { - __internals: { kibanaMigrator: migrator, savedObjectsClientProvider: clientProvider }, + __internals: { + kibanaMigrator: migrator, + savedObjectsClientProvider: clientProvider, + typeRegistry, + }, + setup: { + core: coreMock.createSetup(), + }, + start: { + core: coreMock.createStart(), + }, }, server: mockServer, ready: () => {}, @@ -124,14 +165,7 @@ describe('Saved Objects Mixin', () => { }, uiExports: { savedObjectMappings, - savedObjectSchemas: { - hiddentype: { - hidden: true, - }, - doc1: { - indexPattern: 'other-index', - }, - }, + savedObjectSchemas, }, }; }); diff --git a/src/legacy/ui/public/agg_response/tabify/_get_columns.ts b/src/legacy/ui/public/agg_response/tabify/_get_columns.ts index a3127c039049b..4144d5be16012 100644 --- a/src/legacy/ui/public/agg_response/tabify/_get_columns.ts +++ b/src/legacy/ui/public/agg_response/tabify/_get_columns.ts @@ -18,15 +18,15 @@ */ import { groupBy } from 'lodash'; -import { AggConfig } from '../../agg_types'; +import { IAggConfig } from '../../agg_types'; export interface AggColumn { - aggConfig: AggConfig; + aggConfig: IAggConfig; id: string; name: string; } -const getColumn = (agg: AggConfig, i: number): AggColumn => { +const getColumn = (agg: IAggConfig, i: number): AggColumn => { return { aggConfig: agg, id: `col-${i}-${agg.id}`, @@ -40,7 +40,7 @@ const getColumn = (agg: AggConfig, i: number): AggColumn => { * @param {AggConfigs} aggs - the agg configs object to which the aggregation response correlates * @param {boolean} minimalColumns - setting to true will only return a column for the last bucket/metric instead of one for each level */ -export function tabifyGetColumns(aggs: AggConfig[], minimalColumns: boolean) { +export function tabifyGetColumns(aggs: IAggConfig[], minimalColumns: boolean) { // pick the columns if (minimalColumns) { return aggs.map((agg, i) => getColumn(agg, i)); diff --git a/src/legacy/ui/public/agg_types/index.ts b/src/legacy/ui/public/agg_types/index.ts index cf2733b9a9f36..ac5d0bed7ef15 100644 --- a/src/legacy/ui/public/agg_types/index.ts +++ b/src/legacy/ui/public/agg_types/index.ts @@ -17,15 +17,69 @@ * under the License. */ -export { aggTypes } from './agg_types'; -export { AggParam } from './agg_params'; -export { AggConfig } from './agg_config'; -export { AggConfigs } from './agg_configs'; -export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; -export { FieldParamType } from './param_types'; -export { BUCKET_TYPES } from './buckets/bucket_agg_types'; -export { METRIC_TYPES } from './metrics/metric_agg_types'; -export { ISchemas, Schema, Schemas } from './schemas'; -export { AggType } from './agg_type'; -export { setBounds } from './buckets/date_histogram'; -export { termsAggFilter } from './buckets/terms'; +/** + * Nothing to see here! + * + * Agg Types have moved to the data plugin, and are being + * re-exported from ui/agg_types for backwards compatibility. + */ + +import { start as dataStart } from '../../../core_plugins/data/public/legacy'; + +// runtime contracts +export const { + types: aggTypes, + AggConfig, + AggConfigs, + AggType, + aggTypeFieldFilters, + FieldParamType, + MetricAggType, + parentPipelineAggHelper, + siblingPipelineAggHelper, + setBounds, +} = dataStart.search.aggs; + +// types +export { + IAggConfig, + IAggConfigs, + IAggType, + IFieldParamType, + IMetricAggType, + AggParam, + AggParamOption, + BUCKET_TYPES, + DateRangeKey, + IpRangeKey, + ISchemas, + METRIC_TYPES, + OptionedParamEditorProps, + OptionedValueProp, +} from '../../../core_plugins/data/public'; + +// static code +export { + AggParamType, + AggTypeFilters, + aggTypeFilters, + AggTypeFieldFilters, + AggGroupNames, + aggGroupNamesMap, + CidrMask, + convertDateRangeToString, + convertIPRangeToString, + intervalOptions, + isDateHistogramBucketAggConfig, + isStringType, + isType, + isValidInterval, + isValidJson, + OptionedParamType, + parentPipelineType, + propFilter, + Schema, + Schemas, + siblingPipelineType, + termsAggFilter, +} from '../../../core_plugins/data/public'; diff --git a/src/legacy/ui/public/chrome/api/nav.ts b/src/legacy/ui/public/chrome/api/nav.ts index 771314d9e1481..ae32473e451b7 100644 --- a/src/legacy/ui/public/chrome/api/nav.ts +++ b/src/legacy/ui/public/chrome/api/nav.ts @@ -146,7 +146,7 @@ export function initChromeNavApi(chrome: any, internals: NavInternals) { // link.active and link.lastUrl properties coreNavLinks .getAll() - .filter(link => link.subUrlBase) + .filter(link => link.subUrlBase && !link.disableSubUrlTracking) .forEach(link => { coreNavLinks.update(link.id, { subUrlBase: relativeToAbsolute(chrome.addBasePath(link.subUrlBase)), diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.js.snap index c0954491a2a47..729487dfae5d7 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.js.snap @@ -21,6 +21,7 @@ exports[`TruncateFormatEditor should render normally 1`] = ` > diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.js index fdae8627ead69..9a9b6c954b78d 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.js @@ -38,7 +38,7 @@ export class TruncateFormatEditor extends DefaultFormatEditor { } render() { - const { formatParams } = this.props; + const { formatParams, onError } = this.props; const { error, samples } = this.state; return ( @@ -55,8 +55,15 @@ export class TruncateFormatEditor extends DefaultFormatEditor { > { - this.onChange({ fieldLength: e.target.value ? Number(e.target.value) : null }); + if (e.target.checkValidity()) { + this.onChange({ + fieldLength: e.target.value ? Number(e.target.value) : null, + }); + } else { + onError(e.target.validationMessage); + } }} isInvalid={!!error} /> diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.test.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.test.js index e98dd4edca386..7ab6f2a9cbeb0 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.test.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.test.js @@ -19,6 +19,7 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { EuiFieldNumber } from '@elastic/eui'; import { TruncateFormatEditor } from './truncate'; @@ -34,6 +35,11 @@ const onChange = jest.fn(); const onError = jest.fn(); describe('TruncateFormatEditor', () => { + beforeEach(() => { + onChange.mockClear(); + onError.mockClear(); + }); + it('should have a formatId', () => { expect(TruncateFormatEditor.formatId).toEqual('truncate'); }); @@ -50,4 +56,54 @@ describe('TruncateFormatEditor', () => { ); expect(component).toMatchSnapshot(); }); + + it('should fire error, when input is invalid', async () => { + const component = shallow( + + ); + const input = component.find(EuiFieldNumber); + + const changeEvent = { + target: { + value: '123.3', + checkValidity: () => false, + validationMessage: 'Error!', + }, + }; + await input.invoke('onChange')(changeEvent); + + expect(onError).toBeCalledWith(changeEvent.target.validationMessage); + expect(onChange).not.toBeCalled(); + }); + + it('should fire change, when input changed and is valid', async () => { + const component = shallow( + + ); + const input = component.find(EuiFieldNumber); + + const changeEvent = { + target: { + value: '123', + checkValidity: () => true, + validationMessage: null, + }, + }; + onError.mockClear(); + await input.invoke('onChange')(changeEvent); + expect(onError).not.toBeCalled(); + expect(onChange).toBeCalledWith({ fieldLength: 123 }); + }); }); diff --git a/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js b/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js index 0788afd5f74eb..12c3ca2acc3cd 100644 --- a/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js +++ b/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js @@ -92,6 +92,7 @@ export const createTopNavHelper = ({ TopNavMenu }) => reactDirective => { ['onClearSavedQuery', { watchDepth: 'reference' }], ['onSaved', { watchDepth: 'reference' }], ['onSavedQueryUpdated', { watchDepth: 'reference' }], + ['onSavedQueryIdChange', { watchDepth: 'reference' }], ['indexPatterns', { watchDepth: 'collection' }], ['filters', { watchDepth: 'collection' }], @@ -109,10 +110,14 @@ export const createTopNavHelper = ({ TopNavMenu }) => reactDirective => { 'screenTitle', 'dateRangeFrom', 'dateRangeTo', + 'savedQueryId', 'isRefreshPaused', 'refreshInterval', 'disableAutoFocus', 'showAutoRefreshOnly', + + // temporary flag to use the stateful components + 'useDefaultBehaviors', ]); }; diff --git a/src/legacy/ui/public/management/index.d.ts b/src/legacy/ui/public/management/index.d.ts index 7880e1d5d0295..529efd36623a3 100644 --- a/src/legacy/ui/public/management/index.d.ts +++ b/src/legacy/ui/public/management/index.d.ts @@ -18,15 +18,7 @@ */ declare module 'ui/management' { - export const PAGE_TITLE_COMPONENT: string; - export const PAGE_SUBTITLE_COMPONENT: string; - export const PAGE_FOOTER_COMPONENT: string; export const SidebarNav: React.FC; - export function registerSettingsComponent( - id: string, - component: string | React.FC, - allowOverride: boolean - ): void; export const management: any; // TODO - properly provide types export const MANAGEMENT_BREADCRUMB: { text: string; diff --git a/src/legacy/ui/public/management/index.js b/src/legacy/ui/public/management/index.js index b2f1946dbc59c..25d3678c5dbba 100644 --- a/src/legacy/ui/public/management/index.js +++ b/src/legacy/ui/public/management/index.js @@ -17,12 +17,6 @@ * under the License. */ -export { - PAGE_TITLE_COMPONENT, - PAGE_SUBTITLE_COMPONENT, - PAGE_FOOTER_COMPONENT, -} from '../../../core_plugins/kibana/public/management/sections/settings/components/default_component_registry'; -export { registerSettingsComponent } from '../../../core_plugins/kibana/public/management/sections/settings/components/component_registry'; export { MANAGEMENT_BREADCRUMB } from './breadcrumbs'; import { npStart } from 'ui/new_platform'; export const management = npStart.plugins.management.legacy; diff --git a/src/legacy/ui/public/new_platform/__mocks__/helpers.ts b/src/legacy/ui/public/new_platform/__mocks__/helpers.ts index 439ac9b5713df..6f6b4be86f58d 100644 --- a/src/legacy/ui/public/new_platform/__mocks__/helpers.ts +++ b/src/legacy/ui/public/new_platform/__mocks__/helpers.ts @@ -29,6 +29,7 @@ import { managementPluginMock } from '../../../../../plugins/management/public/m import { usageCollectionPluginMock } from '../../../../../plugins/usage_collection/public/mocks'; import { kibanaLegacyPluginMock } from '../../../../../plugins/kibana_legacy/public/mocks'; import { chartPluginMock } from '../../../../../plugins/charts/public/mocks'; +import { advancedSettingsMock } from '../../../../../plugins/advanced_settings/public/mocks'; /* eslint-enable @kbn/eslint/no-restricted-paths */ export const pluginsMock = { @@ -41,7 +42,8 @@ export const pluginsMock = { expressions: expressionsPluginMock.createSetupContract(), uiActions: uiActionsPluginMock.createSetupContract(), usageCollection: usageCollectionPluginMock.createSetupContract(), - kibana_legacy: kibanaLegacyPluginMock.createSetupContract(), + advancedSettings: advancedSettingsMock.createSetupContract(), + kibanaLegacy: kibanaLegacyPluginMock.createSetupContract(), }), createStart: () => ({ data: dataPluginMock.createStartContract(), @@ -52,7 +54,8 @@ export const pluginsMock = { expressions: expressionsPluginMock.createStartContract(), uiActions: uiActionsPluginMock.createStartContract(), management: managementPluginMock.createStartContract(), - kibana_legacy: kibanaLegacyPluginMock.createStartContract(), + advancedSettings: advancedSettingsMock.createStartContract(), + kibanaLegacy: kibanaLegacyPluginMock.createStartContract(), }), }; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index c2c8b5a0fae7a..3cc33504d3daa 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -20,6 +20,7 @@ import sinon from 'sinon'; import { getFieldFormatsRegistry } from '../../../../test_utils/public/stub_field_formats'; import { METRIC_TYPE } from '@kbn/analytics'; +import { ComponentRegistry } from '../../../../../src/plugins/advanced_settings/public/'; const mockObservable = () => { return { @@ -58,6 +59,12 @@ const mockCore = { export const npSetup = { core: mockCore, plugins: { + advancedSettings: { + component: { + register: sinon.fake(), + componentType: ComponentRegistry.componentType, + }, + }, usageCollection: { allowTrackUserAgent: sinon.fake(), reportUiStats: sinon.fake(), @@ -113,10 +120,10 @@ export const npSetup = { share: { register: () => {}, }, - dev_tools: { + devTools: { register: () => {}, }, - kibana_legacy: { + kibanaLegacy: { registerLegacyApp: () => {}, forwardApp: () => {}, config: { @@ -196,10 +203,10 @@ export const npStart = { registerRenderer: sinon.fake(), registerType: sinon.fake(), }, - dev_tools: { + devTools: { getSortedDevTools: () => [], }, - kibana_legacy: { + kibanaLegacy: { getApps: () => [], getForwards: () => [], config: { diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index 2ade98ec54efd..e300ce4a0caf8 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -18,7 +18,7 @@ */ import { IScope } from 'angular'; -import { IUiActionsStart, IUiActionsSetup } from 'src/plugins/ui_actions/public'; +import { UiActionsStart, UiActionsSetup } from 'src/plugins/ui_actions/public'; import { IEmbeddableStart, IEmbeddableSetup } from 'src/plugins/embeddable/public'; import { LegacyCoreSetup, LegacyCoreStart, App, AppMountDeprecated } from '../../../../core/public'; import { Plugin as DataPlugin } from '../../../../plugins/data/public'; @@ -32,6 +32,10 @@ import { DevToolsSetup, DevToolsStart } from '../../../../plugins/dev_tools/publ import { KibanaLegacySetup, KibanaLegacyStart } from '../../../../plugins/kibana_legacy/public'; import { HomePublicPluginSetup, HomePublicPluginStart } from '../../../../plugins/home/public'; import { SharePluginSetup, SharePluginStart } from '../../../../plugins/share/public'; +import { + AdvancedSettingsSetup, + AdvancedSettingsStart, +} from '../../../../plugins/advanced_settings/public'; import { ManagementSetup, ManagementStart } from '../../../../plugins/management/public'; import { BfetchPublicSetup, BfetchPublicStart } from '../../../../plugins/bfetch/public'; import { UsageCollectionSetup } from '../../../../plugins/usage_collection/public'; @@ -48,12 +52,13 @@ export interface PluginsSetup { expressions: ReturnType; home: HomePublicPluginSetup; inspector: InspectorSetup; - uiActions: IUiActionsSetup; + uiActions: UiActionsSetup; navigation: NavigationPublicPluginSetup; - dev_tools: DevToolsSetup; - kibana_legacy: KibanaLegacySetup; + devTools: DevToolsSetup; + kibanaLegacy: KibanaLegacySetup; share: SharePluginSetup; usageCollection: UsageCollectionSetup; + advancedSettings: AdvancedSettingsSetup; management: ManagementSetup; } @@ -65,12 +70,13 @@ export interface PluginsStart { expressions: ReturnType; home: HomePublicPluginStart; inspector: InspectorStart; - uiActions: IUiActionsStart; + uiActions: UiActionsStart; navigation: NavigationPublicPluginStart; - dev_tools: DevToolsStart; - kibana_legacy: KibanaLegacyStart; + devTools: DevToolsStart; + kibanaLegacy: KibanaLegacyStart; share: SharePluginStart; management: ManagementStart; + advancedSettings: AdvancedSettingsStart; } export const npSetup = { diff --git a/src/legacy/ui/public/saved_objects/_index.scss b/src/legacy/ui/public/saved_objects/_index.scss index 50a192b6a7b17..89cda29f67744 100644 --- a/src/legacy/ui/public/saved_objects/_index.scss +++ b/src/legacy/ui/public/saved_objects/_index.scss @@ -1 +1 @@ -@import '../../../../plugins/kibana_react/public/saved_objects/index'; +@import '../../../../plugins/saved_objects/public/index'; diff --git a/src/legacy/ui/public/time_buckets/time_buckets.js b/src/legacy/ui/public/time_buckets/time_buckets.js index 50a57d866099e..a611de45fa859 100644 --- a/src/legacy/ui/public/time_buckets/time_buckets.js +++ b/src/legacy/ui/public/time_buckets/time_buckets.js @@ -144,7 +144,7 @@ TimeBuckets.prototype.getDuration = function() { * generated. * * Input can be one of the following: - * - Any object from src/legacy/ui/agg_types/buckets/_interval_options.js + * - Any object from src/legacy/ui/agg_types.js * - "auto" * - Pass a valid moment unit * - a moment.duration object. diff --git a/src/legacy/ui/public/vis/__tests__/_agg_config.js b/src/legacy/ui/public/vis/__tests__/_agg_config.js index 2ccbaf6c1645e..7dccf3eec18aa 100644 --- a/src/legacy/ui/public/vis/__tests__/_agg_config.js +++ b/src/legacy/ui/public/vis/__tests__/_agg_config.js @@ -21,8 +21,8 @@ import sinon from 'sinon'; import expect from '@kbn/expect'; import ngMock from 'ng_mock'; import { Vis } from '../../../../core_plugins/visualizations/public'; -import { AggType } from '../../agg_types/agg_type'; -import { AggConfig } from '../../agg_types/agg_config'; +import { AggType, AggConfig } from '../../agg_types'; + import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; describe('AggConfig', function() { diff --git a/src/legacy/ui/public/vis/config/editor_config_providers.test.ts b/src/legacy/ui/public/vis/config/editor_config_providers.test.ts deleted file mode 100644 index 9d93930c09ebc..0000000000000 --- a/src/legacy/ui/public/vis/config/editor_config_providers.test.ts +++ /dev/null @@ -1,210 +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 { AggConfig } from 'ui/agg_types'; -import { EditorConfigProviderRegistry } from './editor_config_providers'; -import { EditorParamConfig, FixedParam, NumericIntervalParam, TimeIntervalParam } from './types'; - -jest.mock('ui/new_platform'); - -describe('EditorConfigProvider', () => { - let registry: EditorConfigProviderRegistry; - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: [ - { - name: 'response', - type: 'number', - esTypes: ['integer'], - aggregatable: true, - filterable: true, - searchable: true, - }, - ], - } as any; - - beforeEach(() => { - registry = new EditorConfigProviderRegistry(); - }); - - it('should call registered providers with given parameters', () => { - const provider = jest.fn(() => ({})); - registry.register(provider); - expect(provider).not.toHaveBeenCalled(); - const aggConfig = {} as AggConfig; - registry.getConfigForAgg(indexPattern, aggConfig); - expect(provider).toHaveBeenCalledWith(indexPattern, aggConfig); - }); - - it('should call all registered providers with given parameters', () => { - const provider = jest.fn(() => ({})); - const provider2 = jest.fn(() => ({})); - registry.register(provider); - registry.register(provider2); - expect(provider).not.toHaveBeenCalled(); - expect(provider2).not.toHaveBeenCalled(); - const aggConfig = {} as AggConfig; - registry.getConfigForAgg(indexPattern, aggConfig); - expect(provider).toHaveBeenCalledWith(indexPattern, aggConfig); - expect(provider2).toHaveBeenCalledWith(indexPattern, aggConfig); - }); - - describe('merging configs', () => { - function singleConfig(paramConfig: EditorParamConfig) { - return () => ({ singleParam: paramConfig }); - } - - function getOutputConfig(reg: EditorConfigProviderRegistry) { - return reg.getConfigForAgg(indexPattern, {} as AggConfig).singleParam; - } - - it('should have hidden true if at least one config was hidden true', () => { - registry.register(singleConfig({ hidden: false })); - registry.register(singleConfig({ hidden: true })); - registry.register(singleConfig({ hidden: false })); - const config = getOutputConfig(registry); - expect(config.hidden).toBe(true); - }); - - it('should merge the same fixed values', () => { - registry.register(singleConfig({ fixedValue: 'foo' })); - registry.register(singleConfig({ fixedValue: 'foo' })); - const config = getOutputConfig(registry) as FixedParam; - expect(config).toHaveProperty('fixedValue'); - expect(config.fixedValue).toBe('foo'); - }); - - it('should throw having different fixed values', () => { - registry.register(singleConfig({ fixedValue: 'foo' })); - registry.register(singleConfig({ fixedValue: 'bar' })); - expect(() => { - getOutputConfig(registry); - }).toThrowError(); - }); - - it('should allow same base values', () => { - registry.register(singleConfig({ base: 5 })); - registry.register(singleConfig({ base: 5 })); - const config = getOutputConfig(registry) as NumericIntervalParam; - expect(config).toHaveProperty('base'); - expect(config.base).toBe(5); - }); - - it('should merge multiple base values, using least common multiple', () => { - registry.register(singleConfig({ base: 2 })); - registry.register(singleConfig({ base: 5 })); - registry.register(singleConfig({ base: 8 })); - const config = getOutputConfig(registry) as NumericIntervalParam; - expect(config).toHaveProperty('base'); - expect(config.base).toBe(40); - }); - - it('should throw on combining fixedValue with base', () => { - registry.register(singleConfig({ fixedValue: 'foo' })); - registry.register(singleConfig({ base: 5 })); - expect(() => { - getOutputConfig(registry); - }).toThrowError(); - }); - - it('should allow same timeBase values', () => { - registry.register(singleConfig({ timeBase: '2h', default: '2h' })); - registry.register(singleConfig({ timeBase: '2h', default: '2h' })); - const config = getOutputConfig(registry) as TimeIntervalParam; - expect(config).toHaveProperty('timeBase'); - expect(config).toHaveProperty('default'); - expect(config.timeBase).toBe('2h'); - expect(config.default).toBe('2h'); - }); - - it('should merge multiple compatible timeBase values, using least common interval', () => { - registry.register(singleConfig({ timeBase: '2h', default: '2h' })); - registry.register(singleConfig({ timeBase: '3h', default: '3h' })); - registry.register(singleConfig({ timeBase: '4h', default: '4h' })); - const config = getOutputConfig(registry) as TimeIntervalParam; - expect(config).toHaveProperty('timeBase'); - expect(config).toHaveProperty('default'); - expect(config.timeBase).toBe('12h'); - expect(config.default).toBe('12h'); - }); - - it('should throw on combining incompatible timeBase values', () => { - registry.register(singleConfig({ timeBase: '2h', default: '2h' })); - registry.register(singleConfig({ timeBase: '1d', default: '1d' })); - expect(() => { - getOutputConfig(registry); - }).toThrowError(); - }); - - it('should throw on invalid timeBase values', () => { - registry.register(singleConfig({ timeBase: '2w', default: '2w' })); - expect(() => { - getOutputConfig(registry); - }).toThrowError(); - }); - - it('should throw if timeBase and default are different', () => { - registry.register(singleConfig({ timeBase: '1h', default: '2h' })); - expect(() => { - getOutputConfig(registry); - }).toThrowError(); - }); - - it('should merge hidden together with fixedValue', () => { - registry.register(singleConfig({ fixedValue: 'foo', hidden: true })); - registry.register(singleConfig({ fixedValue: 'foo', hidden: false })); - const config = getOutputConfig(registry) as FixedParam; - expect(config).toHaveProperty('fixedValue'); - expect(config).toHaveProperty('hidden'); - expect(config.fixedValue).toBe('foo'); - expect(config.hidden).toBe(true); - }); - - it('should merge hidden together with base', () => { - registry.register(singleConfig({ base: 2, hidden: false })); - registry.register(singleConfig({ base: 13, hidden: false })); - const config = getOutputConfig(registry) as NumericIntervalParam; - expect(config).toHaveProperty('base'); - expect(config).toHaveProperty('hidden'); - expect(config.base).toBe(26); - expect(config.hidden).toBe(false); - }); - - it('should merge hidden together with timeBase', () => { - registry.register(singleConfig({ timeBase: '2h', default: '2h', hidden: false })); - registry.register(singleConfig({ timeBase: '4h', default: '4h', hidden: false })); - const config = getOutputConfig(registry) as TimeIntervalParam; - expect(config).toHaveProperty('timeBase'); - expect(config).toHaveProperty('default'); - expect(config).toHaveProperty('hidden'); - expect(config.timeBase).toBe('4h'); - expect(config.default).toBe('4h'); - expect(config.hidden).toBe(false); - }); - - it('should merge helps together into one string', () => { - registry.register(singleConfig({ help: 'Warning' })); - registry.register(singleConfig({ help: 'Another help' })); - const config = getOutputConfig(registry); - expect(config).toHaveProperty('help'); - expect(config.help).toBe('Warning\n\nAnother help'); - }); - }); -}); diff --git a/src/legacy/ui/public/vis/config/editor_config_providers.ts b/src/legacy/ui/public/vis/config/editor_config_providers.ts deleted file mode 100644 index 1e82a3ca2762e..0000000000000 --- a/src/legacy/ui/public/vis/config/editor_config_providers.ts +++ /dev/null @@ -1,168 +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 { IndexPattern } from 'src/plugins/data/public'; -import { AggConfig } from 'ui/agg_types'; -import { parseEsInterval } from '../../../../core_plugins/data/public'; -import { - TimeIntervalParam, - EditorConfig, - EditorParamConfig, - FixedParam, - NumericIntervalParam, -} from './types'; -import { leastCommonInterval, leastCommonMultiple } from '../lib'; - -type EditorConfigProvider = (indexPattern: IndexPattern, aggConfig: AggConfig) => EditorConfig; - -class EditorConfigProviderRegistry { - private providers: Set = new Set(); - - public register(configProvider: EditorConfigProvider): void { - this.providers.add(configProvider); - } - - public getConfigForAgg(indexPattern: IndexPattern, aggConfig: AggConfig): EditorConfig { - const configs = Array.from(this.providers).map(provider => provider(indexPattern, aggConfig)); - return this.mergeConfigs(configs); - } - - private isTimeBaseParam(config: EditorParamConfig): config is TimeIntervalParam { - return config.hasOwnProperty('default') && config.hasOwnProperty('timeBase'); - } - - private isBaseParam(config: EditorParamConfig): config is NumericIntervalParam { - return config.hasOwnProperty('base'); - } - - private isFixedParam(config: EditorParamConfig): config is FixedParam { - return config.hasOwnProperty('fixedValue'); - } - - private mergeHidden(current: EditorParamConfig, merged: EditorParamConfig): boolean { - return Boolean(current.hidden || merged.hidden); - } - - private mergeHelp(current: EditorParamConfig, merged: EditorParamConfig): string | undefined { - if (!current.help) { - return merged.help; - } - - return merged.help ? `${merged.help}\n\n${current.help}` : current.help; - } - - private mergeFixedAndBase( - current: EditorParamConfig, - merged: EditorParamConfig, - paramName: string - ): { fixedValue: unknown } | { base: number } | {} { - if ( - this.isFixedParam(current) && - this.isFixedParam(merged) && - current.fixedValue !== merged.fixedValue - ) { - // In case multiple configurations provided a fixedValue, these must all be the same. - // If not we'll throw an error. - throw new Error(`Two EditorConfigProviders provided different fixed values for field ${paramName}: - ${merged.fixedValue} !== ${current.fixedValue}`); - } - - if ( - (this.isFixedParam(current) && this.isBaseParam(merged)) || - (this.isBaseParam(current) && this.isFixedParam(merged)) - ) { - // In case one config tries to set a fixed value and another setting a base value, - // we'll throw an error. This could be solved more elegantly, by allowing fixedValues - // that are the multiple of the specific base value, but since there is no use-case for that - // right now, this isn't implemented. - throw new Error(`Tried to provide a fixedValue and a base for param ${paramName}.`); - } - - if (this.isBaseParam(current) && this.isBaseParam(merged)) { - // In case where both had interval values, just use the least common multiple between both interval - return { - base: leastCommonMultiple(current.base, merged.base), - }; - } - - // In this case we haven't had a fixed value of base for that param yet, we use the one specified - // in the current config - if (this.isFixedParam(current)) { - return { - fixedValue: current.fixedValue, - }; - } - if (this.isBaseParam(current)) { - return { - base: current.base, - }; - } - - return {}; - } - - private mergeTimeBase( - current: TimeIntervalParam, - merged: EditorParamConfig, - paramName: string - ): { timeBase: string; default: string } { - if (current.default !== current.timeBase) { - throw new Error(`Tried to provide differing default and timeBase values for ${paramName}.`); - } - - if (this.isTimeBaseParam(merged)) { - // In case both had where interval values, just use the least common multiple between both intervals - const timeBase = leastCommonInterval(current.timeBase, merged.timeBase); - return { - default: timeBase, - timeBase, - }; - } - - // This code is simply here to throw an error in case the `timeBase` is not a valid ES interval - parseEsInterval(current.timeBase); - return { - default: current.timeBase, - timeBase: current.timeBase, - }; - } - - private mergeConfigs(configs: EditorConfig[]): EditorConfig { - return configs.reduce((output, conf) => { - Object.entries(conf).forEach(([paramName, paramConfig]) => { - if (!output[paramName]) { - output[paramName] = {}; - } - - output[paramName] = { - hidden: this.mergeHidden(paramConfig, output[paramName]), - help: this.mergeHelp(paramConfig, output[paramName]), - ...(this.isTimeBaseParam(paramConfig) - ? this.mergeTimeBase(paramConfig, output[paramName], paramName) - : this.mergeFixedAndBase(paramConfig, output[paramName], paramName)), - }; - }); - return output; - }, {}); - } -} - -const editorConfigProviders = new EditorConfigProviderRegistry(); - -export { editorConfigProviders, EditorConfigProviderRegistry }; diff --git a/src/legacy/ui/public/vis/config/types.ts b/src/legacy/ui/public/vis/config/types.ts deleted file mode 100644 index 61c0ced3cd519..0000000000000 --- a/src/legacy/ui/public/vis/config/types.ts +++ /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. - */ - -/** - * A hidden parameter can be hidden from the UI completely. - */ -interface Param { - hidden?: boolean; - help?: string; -} - -/** - * A fixed parameter has a fixed value for a specific field. - * It can optionally also be hidden. - */ -export type FixedParam = Partial & { - fixedValue: any; -}; - -/** - * Numeric interval parameters must always be set in the editor to a multiple of - * the specified base. It can optionally also be hidden. - */ -export type NumericIntervalParam = Partial & { - base: number; -}; - -/** - * Time interval parameters must always be set in the editor to a multiple of - * the specified base. It can optionally also be hidden. - */ -export type TimeIntervalParam = Partial & { - default: string; - timeBase: string; -}; - -export type EditorParamConfig = NumericIntervalParam | TimeIntervalParam | FixedParam | Param; - -export interface EditorConfig { - [paramName: string]: EditorParamConfig; -} diff --git a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts index e763eb1b90791..d8227343159e6 100644 --- a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts +++ b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts @@ -19,15 +19,15 @@ import { i18n } from '@kbn/i18n'; import { identity } from 'lodash'; -import { AggConfig } from 'ui/agg_types'; +import { IAggConfig } from 'ui/agg_types'; import { npStart } from 'ui/new_platform'; import { SerializedFieldFormat } from 'src/plugins/expressions/public'; import { fieldFormats } from '../../../../../../plugins/data/public'; import { Vis } from '../../../../../core_plugins/visualizations/public'; import { tabifyGetColumns } from '../../../agg_response/tabify/_get_columns'; -import { DateRangeKey, convertDateRangeToString } from '../../../agg_types/buckets/date_range'; -import { IpRangeKey, convertIPRangeToString } from '../../../agg_types/buckets/ip_range'; +import { DateRangeKey, convertDateRangeToString } from '../../../agg_types'; +import { IpRangeKey, convertIPRangeToString } from '../../../agg_types'; interface TermsFieldFormatParams { otherBucketLabel: string; @@ -62,7 +62,7 @@ const getFieldFormat = ( return new DefaultFieldFormat(); }; -export const createFormat = (agg: AggConfig): SerializedFieldFormat => { +export const createFormat = (agg: IAggConfig): SerializedFieldFormat => { const format: SerializedFieldFormat = agg.params.field ? agg.params.field.format.toJSON() : {}; const formats: Record SerializedFieldFormat> = { date_range: () => ({ id: 'date_range', params: format }), @@ -106,7 +106,7 @@ export const getFormat: FormatFactory = mapping => { const format = getFieldFormat(id, mapping.params); const gte = '\u2265'; const lt = '\u003c'; - return i18n.translate('common.ui.aggTypes.buckets.ranges.rangesFormatMessage', { + return i18n.translate('common.ui.aggTypes.rangesFormatMessage', { defaultMessage: '{gte} {from} and {lt} {to}', values: { gte, @@ -155,7 +155,7 @@ export const getFormat: FormatFactory = mapping => { } }; -export const getTableAggs = (vis: Vis): AggConfig[] => { +export const getTableAggs = (vis: Vis): IAggConfig[] => { if (!vis.aggs || !vis.aggs.getResponseAggs) { return []; } diff --git a/src/optimize/base_optimizer.js b/src/optimize/base_optimizer.js index efff7f0aa2b46..d9df2a1955df3 100644 --- a/src/optimize/base_optimizer.js +++ b/src/optimize/base_optimizer.js @@ -256,6 +256,7 @@ export default class BaseOptimizer { profile: this.profile || false, output: { + futureEmitAssets: true, // TODO: remove on webpack 5 path: this.uiBundles.getWorkingDir(), filename: '[name].bundle.js', sourceMapFilename: '[file].map', diff --git a/src/optimize/dynamic_dll_plugin/dll_config_model.js b/src/optimize/dynamic_dll_plugin/dll_config_model.js index c7ab2fe30dd14..3e31b0a7a2ead 100644 --- a/src/optimize/dynamic_dll_plugin/dll_config_model.js +++ b/src/optimize/dynamic_dll_plugin/dll_config_model.js @@ -48,6 +48,7 @@ function generateDLL(config) { entry: dllEntry, context: dllContext, output: { + futureEmitAssets: true, // TODO: remove on webpack 5 filename: dllBundleFilename, path: dllOutputPath, publicPath: dllPublicPath, diff --git a/src/plugins/advanced_settings/kibana.json b/src/plugins/advanced_settings/kibana.json new file mode 100644 index 0000000000000..5fc1e916ae45f --- /dev/null +++ b/src/plugins/advanced_settings/kibana.json @@ -0,0 +1,7 @@ +{ + "id": "advancedSettings", + "version": "kibana", + "server": false, + "ui": true, + "requiredPlugins": [] +} diff --git a/src/plugins/advanced_settings/public/component_registry/__snapshots__/component_registry.test.tsx.snap b/src/plugins/advanced_settings/public/component_registry/__snapshots__/component_registry.test.tsx.snap new file mode 100644 index 0000000000000..1d6cc882cb344 --- /dev/null +++ b/src/plugins/advanced_settings/public/component_registry/__snapshots__/component_registry.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ComponentRegistry register should disallow registering a component with a duplicate id 1`] = `"Component with id advanced_settings_page_title is already registered."`; diff --git a/src/plugins/advanced_settings/public/component_registry/component_registry.test.tsx b/src/plugins/advanced_settings/public/component_registry/component_registry.test.tsx new file mode 100644 index 0000000000000..3b722e9517fdb --- /dev/null +++ b/src/plugins/advanced_settings/public/component_registry/component_registry.test.tsx @@ -0,0 +1,90 @@ +/* + * 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 React from 'react'; +import { ComponentRegistry } from './component_registry'; + +describe('ComponentRegistry', () => { + describe('register', () => { + it('should allow a component to be registered', () => { + const component = () =>
; + new ComponentRegistry().setup.register( + ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, + component + ); + }); + + it('should disallow registering a component with a duplicate id', () => { + const registry = new ComponentRegistry(); + const component = () =>
; + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + expect(() => + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, () => ( + + )) + ).toThrowErrorMatchingSnapshot(); + }); + + it('should allow a component to be overriden', () => { + const registry = new ComponentRegistry(); + const component = () =>
; + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + + const anotherComponent = () => ; + registry.setup.register( + ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, + anotherComponent, + true + ); + + expect(registry.start.get(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT)).toBe( + anotherComponent + ); + }); + }); + + describe('get', () => { + it('should allow a component to be retrieved', () => { + const registry = new ComponentRegistry(); + const component = () =>
; + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + expect(registry.start.get(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT)).toBe( + component + ); + }); + }); + + it('should set a displayName for the component if one does not exist', () => { + const component: React.ComponentType = () =>
; + const registry = new ComponentRegistry(); + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + + expect(component.displayName).toEqual(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT); + }); + + it('should not set a displayName for the component if one already exists', () => { + const component: React.ComponentType = () =>
; + component.displayName = ''; + const registry = new ComponentRegistry(); + + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + + expect(component.displayName).toEqual(''); + }); +}); diff --git a/src/plugins/advanced_settings/public/component_registry/component_registry.ts b/src/plugins/advanced_settings/public/component_registry/component_registry.ts new file mode 100644 index 0000000000000..cc61798e84cb7 --- /dev/null +++ b/src/plugins/advanced_settings/public/component_registry/component_registry.ts @@ -0,0 +1,91 @@ +/* + * 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 { ComponentType } from 'react'; +import { PageTitle } from './page_title'; +import { PageSubtitle } from './page_subtitle'; +import { PageFooter } from './page_footer'; + +type Id = + | 'advanced_settings_page_title' + | 'advanced_settings_page_subtitle' + | 'advanced_settings_page_footer'; + +const componentType: { [key: string]: Id } = { + PAGE_TITLE_COMPONENT: 'advanced_settings_page_title' as Id, + PAGE_SUBTITLE_COMPONENT: 'advanced_settings_page_subtitle' as Id, + PAGE_FOOTER_COMPONENT: 'advanced_settings_page_footer' as Id, +}; + +type RegistryComponent = ComponentType | undefined>; + +export class ComponentRegistry { + static readonly componentType = componentType; + static readonly defaultRegistry: Record = { + advanced_settings_page_title: PageTitle, + advanced_settings_page_subtitle: PageSubtitle, + advanced_settings_page_footer: PageFooter, + }; + + registry: { [key in Id]?: RegistryComponent } = {}; + + /** + * Attempts to register the provided component, with the ability to optionally allow + * the component to override an existing one. + * + * If the intent is to override, then `allowOverride` must be set to true, otherwise an exception is thrown. + * + * @param {*} id the id of the component to register + * @param {*} component the component + * @param {*} allowOverride (default: false) - optional flag to allow this component to override a previously registered component + */ + private register(id: Id, component: RegistryComponent, allowOverride = false) { + if (!allowOverride && id in this.registry) { + throw new Error(`Component with id ${id} is already registered.`); + } + + // Setting a display name if one does not already exist. + // This enhances the snapshots, as well as the debugging experience. + if (!component.displayName) { + component.displayName = id; + } + + this.registry[id] = component; + } + + /** + * Retrieve a registered component by its ID. + * If the component does not exist, then an exception is thrown. + * + * @param {*} id the ID of the component to retrieve + */ + private get(id: Id): RegistryComponent { + return this.registry[id] || ComponentRegistry.defaultRegistry[id]; + } + + setup = { + componentType: ComponentRegistry.componentType, + register: this.register.bind(this), + }; + + start = { + componentType: ComponentRegistry.componentType, + get: this.get.bind(this), + }; +} diff --git a/src/legacy/ui/public/vis/config/index.ts b/src/plugins/advanced_settings/public/component_registry/index.ts similarity index 86% rename from src/legacy/ui/public/vis/config/index.ts rename to src/plugins/advanced_settings/public/component_registry/index.ts index ee7385518a85d..79c9248e0c2a9 100644 --- a/src/legacy/ui/public/vis/config/index.ts +++ b/src/plugins/advanced_settings/public/component_registry/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export { editorConfigProviders, EditorConfigProviderRegistry } from './editor_config_providers'; -export * from './types'; +export { ComponentRegistry } from './component_registry'; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/__snapshots__/page_footer.test.tsx.snap b/src/plugins/advanced_settings/public/component_registry/page_footer/__snapshots__/page_footer.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/__snapshots__/page_footer.test.tsx.snap rename to src/plugins/advanced_settings/public/component_registry/page_footer/__snapshots__/page_footer.test.tsx.snap diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/index.ts b/src/plugins/advanced_settings/public/component_registry/page_footer/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/index.ts rename to src/plugins/advanced_settings/public/component_registry/page_footer/index.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.test.tsx b/src/plugins/advanced_settings/public/component_registry/page_footer/page_footer.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.test.tsx rename to src/plugins/advanced_settings/public/component_registry/page_footer/page_footer.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.ts b/src/plugins/advanced_settings/public/component_registry/page_footer/page_footer.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.ts rename to src/plugins/advanced_settings/public/component_registry/page_footer/page_footer.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/__snapshots__/page_subtitle.test.tsx.snap b/src/plugins/advanced_settings/public/component_registry/page_subtitle/__snapshots__/page_subtitle.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/__snapshots__/page_subtitle.test.tsx.snap rename to src/plugins/advanced_settings/public/component_registry/page_subtitle/__snapshots__/page_subtitle.test.tsx.snap diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/index.ts b/src/plugins/advanced_settings/public/component_registry/page_subtitle/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/index.ts rename to src/plugins/advanced_settings/public/component_registry/page_subtitle/index.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.test.tsx b/src/plugins/advanced_settings/public/component_registry/page_subtitle/page_subtitle.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.test.tsx rename to src/plugins/advanced_settings/public/component_registry/page_subtitle/page_subtitle.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.ts b/src/plugins/advanced_settings/public/component_registry/page_subtitle/page_subtitle.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.ts rename to src/plugins/advanced_settings/public/component_registry/page_subtitle/page_subtitle.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/__snapshots__/page_title.test.tsx.snap b/src/plugins/advanced_settings/public/component_registry/page_title/__snapshots__/page_title.test.tsx.snap similarity index 85% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/__snapshots__/page_title.test.tsx.snap rename to src/plugins/advanced_settings/public/component_registry/page_title/__snapshots__/page_title.test.tsx.snap index 8dd4e501067b5..10b799a986b84 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/__snapshots__/page_title.test.tsx.snap +++ b/src/plugins/advanced_settings/public/component_registry/page_title/__snapshots__/page_title.test.tsx.snap @@ -7,7 +7,7 @@ exports[`PageTitle should render normally 1`] = ` > diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/index.ts b/src/plugins/advanced_settings/public/component_registry/page_title/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/index.ts rename to src/plugins/advanced_settings/public/component_registry/page_title/index.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.test.tsx b/src/plugins/advanced_settings/public/component_registry/page_title/page_title.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.test.tsx rename to src/plugins/advanced_settings/public/component_registry/page_title/page_title.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.tsx b/src/plugins/advanced_settings/public/component_registry/page_title/page_title.tsx similarity index 91% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.tsx rename to src/plugins/advanced_settings/public/component_registry/page_title/page_title.tsx index cb807302c2380..18d9c60d331bb 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.tsx +++ b/src/plugins/advanced_settings/public/component_registry/page_title/page_title.tsx @@ -25,7 +25,7 @@ export const PageTitle = () => { return (

- +

); diff --git a/src/plugins/advanced_settings/public/index.ts b/src/plugins/advanced_settings/public/index.ts new file mode 100644 index 0000000000000..13be36e671f75 --- /dev/null +++ b/src/plugins/advanced_settings/public/index.ts @@ -0,0 +1,27 @@ +/* + * 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 { PluginInitializerContext } from 'kibana/public'; +import { AdvancedSettingsPlugin } from './plugin'; +export { AdvancedSettingsSetup, AdvancedSettingsStart } from './types'; +export { ComponentRegistry } from './component_registry'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new AdvancedSettingsPlugin(); +} diff --git a/src/plugins/advanced_settings/public/mocks.ts b/src/plugins/advanced_settings/public/mocks.ts new file mode 100644 index 0000000000000..e147f57101aae --- /dev/null +++ b/src/plugins/advanced_settings/public/mocks.ts @@ -0,0 +1,33 @@ +/* + * 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 { ComponentRegistry } from './component_registry'; + +const register = jest.fn(); +const get = jest.fn(); +const componentType = ComponentRegistry.componentType; + +export const advancedSettingsMock = { + createSetupContract() { + return { register, componentType }; + }, + createStartContract() { + return { get, componentType }; + }, +}; diff --git a/src/plugins/advanced_settings/public/plugin.ts b/src/plugins/advanced_settings/public/plugin.ts new file mode 100644 index 0000000000000..692e515ca4e5e --- /dev/null +++ b/src/plugins/advanced_settings/public/plugin.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 { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { ComponentRegistry } from './component_registry'; +import { AdvancedSettingsSetup, AdvancedSettingsStart } from './types'; + +const component = new ComponentRegistry(); + +export class AdvancedSettingsPlugin + implements Plugin { + public setup(core: CoreSetup) { + return { + component: component.setup, + }; + } + + public start(core: CoreStart) { + return { + component: component.start, + }; + } +} diff --git a/src/legacy/ui/public/saved_objects/components/saved_object_save_modal.tsx b/src/plugins/advanced_settings/public/types.ts similarity index 77% rename from src/legacy/ui/public/saved_objects/components/saved_object_save_modal.tsx rename to src/plugins/advanced_settings/public/types.ts index 131f28059cebd..a9b965c3c22de 100644 --- a/src/legacy/ui/public/saved_objects/components/saved_object_save_modal.tsx +++ b/src/plugins/advanced_settings/public/types.ts @@ -17,9 +17,11 @@ * under the License. */ -/** - * @deprecated - * - * Do not import this component from here. Import from `src/plugins/kibana_react` instead. - */ -export { SavedObjectSaveModal } from '../../../../../plugins/kibana_react/public'; +import { ComponentRegistry } from './component_registry'; + +export interface AdvancedSettingsSetup { + component: ComponentRegistry['setup']; +} +export interface AdvancedSettingsStart { + component: ComponentRegistry['start']; +} diff --git a/src/plugins/console/kibana.json b/src/plugins/console/kibana.json index 18f7eb06e98ed..57de385ba565c 100644 --- a/src/plugins/console/kibana.json +++ b/src/plugins/console/kibana.json @@ -3,6 +3,6 @@ "version": "kibana", "server": true, "ui": true, - "requiredPlugins": ["dev_tools", "home"], + "requiredPlugins": ["devTools", "home"], "optionalPlugins": ["usageCollection"] } diff --git a/src/plugins/console/public/application/components/index.ts b/src/plugins/console/public/application/components/index.ts index eccde899a2640..d9a8aa9328b73 100644 --- a/src/plugins/console/public/application/components/index.ts +++ b/src/plugins/console/public/application/components/index.ts @@ -17,6 +17,7 @@ * under the License. */ +export { NetworkRequestStatusBar } from './network_request_status_bar'; export { SomethingWentWrongCallout } from './something_went_wrong_callout'; export { TopNavMenuItem, TopNavMenu } from './top_nav_menu'; export { ConsoleMenu } from './console_menu'; diff --git a/src/plugins/console/public/application/components/network_request_status_bar/index.ts b/src/plugins/console/public/application/components/network_request_status_bar/index.ts new file mode 100644 index 0000000000000..ce214c1cdfffa --- /dev/null +++ b/src/plugins/console/public/application/components/network_request_status_bar/index.ts @@ -0,0 +1,20 @@ +/* + * 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 { NetworkRequestStatusBar } from './network_request_status_bar'; diff --git a/src/plugins/console/public/application/components/network_request_status_bar/network_request_status_bar.tsx b/src/plugins/console/public/application/components/network_request_status_bar/network_request_status_bar.tsx new file mode 100644 index 0000000000000..6915ff15f374d --- /dev/null +++ b/src/plugins/console/public/application/components/network_request_status_bar/network_request_status_bar.tsx @@ -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 { i18n } from '@kbn/i18n'; +import React, { FunctionComponent } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiBadge, EuiText, EuiToolTip } from '@elastic/eui'; + +export interface Props { + requestInProgress: boolean; + requestResult?: { + // Status code of the request, e.g., 200 + statusCode: number; + + // Status text of the request, e.g., OK + statusText: string; + + // Method of the request, e.g., GET + method: string; + + // The path of endpoint that was called, e.g., /_search + endpoint: string; + + // The time, in milliseconds, that the last request took + timeElapsedMs: number; + }; +} + +const mapStatusCodeToBadgeColor = (statusCode: number) => { + if (statusCode <= 199) { + return 'default'; + } + + if (statusCode <= 299) { + return 'secondary'; + } + + if (statusCode <= 399) { + return 'primary'; + } + + if (statusCode <= 499) { + return 'warning'; + } + + return 'danger'; +}; + +export const NetworkRequestStatusBar: FunctionComponent = ({ + requestInProgress, + requestResult, +}) => { + let content: React.ReactNode = null; + + if (requestInProgress) { + content = ( + + + {i18n.translate('console.requestInProgressBadgeText', { + defaultMessage: 'Request in progress', + })} + + + ); + } else if (requestResult) { + const { endpoint, method, statusCode, statusText, timeElapsedMs } = requestResult; + + content = ( + <> + + {`${method} ${ + endpoint.startsWith('/') ? endpoint : '/' + endpoint + }`} + } + > + + {/* Use   to ensure that no matter the width we don't allow line breaks */} + {statusCode} - {statusText} + + + + + + {i18n.translate('console.requestTimeElapasedBadgeTooltipContent', { + defaultMessage: 'Time Elapsed', + })} + + } + > + + + {timeElapsedMs} {'ms'} + + + + + + ); + } + + return ( + + {content} + + ); +}; diff --git a/src/plugins/console/public/application/containers/editor/editor.tsx b/src/plugins/console/public/application/containers/editor/editor.tsx index 5c7fe293651fb..0bfe837f2cd90 100644 --- a/src/plugins/console/public/application/containers/editor/editor.tsx +++ b/src/plugins/console/public/application/containers/editor/editor.tsx @@ -17,14 +17,15 @@ * under the License. */ -import React, { useCallback } from 'react'; +import React, { useCallback, memo } from 'react'; import { debounce } from 'lodash'; +import { EuiProgress } from '@elastic/eui'; import { EditorContentSpinner } from '../../components'; import { Panel, PanelsContainer } from '../../../../../kibana_react/public'; import { Editor as EditorUI, EditorOutput } from './legacy/console_editor'; import { StorageKeys } from '../../../services'; -import { useEditorReadContext, useServicesContext } from '../../contexts'; +import { useEditorReadContext, useServicesContext, useRequestReadContext } from '../../contexts'; const INITIAL_PANEL_WIDTH = 50; const PANEL_MIN_WIDTH = '100px'; @@ -33,12 +34,13 @@ interface Props { loading: boolean; } -export const Editor = ({ loading }: Props) => { +export const Editor = memo(({ loading }: Props) => { const { services: { storage }, } = useServicesContext(); const { currentTextObject } = useEditorReadContext(); + const { requestInFlight } = useRequestReadContext(); const [firstPanelWidth, secondPanelWidth] = storage.get(StorageKeys.WIDTH, [ INITIAL_PANEL_WIDTH, @@ -55,23 +57,30 @@ export const Editor = ({ loading }: Props) => { if (!currentTextObject) return null; return ( - - - {loading ? ( - - ) : ( - - )} - - - {loading ? : } - - + <> + {requestInFlight ? ( +
+ +
+ ) : null} + + + {loading ? ( + + ) : ( + + )} + + + {loading ? : } + + + ); -}; +}); diff --git a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx index 759e3dbafb39c..b3e966ddffa4c 100644 --- a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx +++ b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx @@ -211,14 +211,14 @@ function EditorUI({ initialTextValue }: EditorProps) {